ZJU 1234 Chopsticks
鉴于四年前写的过于简陋,并且字体较小,故使用CSDN新使用的Markdown编译器在此加上修改。
英文原题:
In China,people use a pair of chopsticks to get food on the table, but Mr. L is a bitdifferent. He uses a set of three chopsticks – one pair, plus an EXTRA longchopstick to get some big food by piercing it through the food. As you mayguess, the length of the two shorter chopsticks should be as close as possible,but the length of the extra one is not important, as long as it’s the longest.To make things clearer, for the set of chopsticks with lengthsA,B,C(A<=B<=C), (A-B)^2 is called the ‘badness’ of the set.
It’s December 2nd, Mr.L’s birthday! He invited K people tojoin his birthday party, and would like to introduce his way of usingchopsticks. So, he should prepare K+8 sets of chopsticks(for himself, his wife,his little son, little daughter, his mother, father, mother-in-law,father-in-law, and K other guests). But Mr.L suddenly discovered that hischopsticks are of quite different lengths! He should find a way of composingthe K+8 sets, so that the total badness of all the sets is minimized.
Input
The first line in the input contains a single integer T,indicating the number of test cases(1<=T<=20). Each test case begins withtwo integers K, N(0<=K<=1000, 3K+24<=N<=5000), the number of guestsand the number of chopsticks. There are N positive integers Li on the next linein non-decreasing order indicating the lengths of thechopsticks.(1<=Li<=32000).
Output
For each test case in the input, print a line containingthe minimal total badness of all the sets.
Sample Input
1
1 40
1 8 10 16 19 22 27 33 36 40 47 52 56 61 63 71 72 75 81 81 84 88 96 98 103 110 113 118 124 128 129 134 134 139 148 157 157 160 162 164
Sample Output
23
Note
For the sample input, a possible collection of the 9 setsis:
8,10,16; 19,22,27; 61,63,75; 71,72,88; 81,81,84; 96,98,103; 128,129,148;134,134,139; 157,157,160
题目大意:
一个怪人,吃东西时使用三个筷子,二短一长,设它们的长为A<=B<=C。并定义它的“坏度”为(A – B) ^ 2.这一天,他要请K个人来家里吃饭,另外他自己家里还有8个人,因而要准备K+8双这种特别的筷子。但发现家里的筷子全是不一样长的。请你将这些筷子分成K+8套,要求总的"坏度"值最小。
其中K<=1000, 3K + 24 <= N <= 5000。
题解:
因为“坏度”= ( A – B ) ^ 2,则我们可以知道这个值与c是无关的,A和B的差绝对值越小,这个坏度肯定就会越小。则我们可以肯定,如果我们把筷子的长度都排序以后,我们选出的A、B都是相邻的。
所以我分为两个状态取讨论
1:讨论关键状态
关键状态很简单,我们考虑状态Opt [ I ] [ J ],如果我们取第J对筷子为Stick [ I ]和Stick[ I – 1 ],则这个状态就是关键状态。
对于关键状态,可以得出方程:
Opt [ I ][ J ] = Opt [ I – 2 ][ J – 1 ] + Sqr ( Stick [ I ] – Stick[ I – 1 ] )
条件和第一方程相同。
2:讨论非关键状态
这个就更简单了,只要不满足关键状态的条件,那这个状态就是个非关键状态。
对于非关键状态,因为Stick [ I ]和Stick [ I – 1 ]不是第J对筷子,所以只可能由Stick [ I – 1 ] 和 Stick [ I – 2 ]或者更前面的筷子组成。可是这个时候我们已经把这些信息都DP出来了,所以我们要充分利用这些信息,所以得到如下方程: Opt [ I , J ] = Opt [ I – 1 ,J ]
但这个方程的条件就和关键状态的方程不同了,其条件改为I > 2 * J,因为如果 I = 2 * J ,那么前面的I根都分成J对,没有任何一根是多余的。所以当 Opt [ I , J ] = Opt [ I – 1 , J ] 时,I一定要大于 2 * J。而以前做决策时,已经保证一定有第三根的存在,所以不须考虑第三根了。
将两个部分合并来:得到最终的方程:
Opt [I ][ J ] = Min ( Opt [ I – 2 ][ J – 1 ] + Sqr ( Stick [ I ] – Stick [ I – 1 ] ) ,Opt [ I – 1 , J ] )
这个方程是O(N ^ 2),满足要求了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5000+10;
int k,n,a[maxn];
int dp[1000+10][maxn];
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&k,&n);
for (int i=n ; i>=1 ; i--)
scanf("%d",&a[i]);
k += 8;
memset(dp,0,sizeof(dp));
for (int i=1 ; i<=k ; i++)
{
dp[i][3*i]=dp[i-1][3*i-2]+(a[3*i-1]-a[3*i])*(a[3*i-1]-a[3*i]);
for (int j=3*i+1 ; j<=n ; j++)
dp[i][j]=min(dp[i][j-1],dp[i-1][j-2]+(a[j-1]-a[j])*(a[j-1]-a[j]));
}
printf("%d\n",dp[k][n]);
}
return 0;
}