题目大意:第一行输入N与K,N<=100,K<50。
第二行输入N个数(每个数均小于等于50)。
目标,从这N个数中选一部分数配成K+3对,代价为每对N之差的平方和,要求代价最小值。
输出:一个值,代表最小代价
思路:一看到这个题,便知道应用动规,然而若直接用动规的话会有后效性(最后一个不知道和谁配对),想到每个数应与自己最相近的数配对。于是将这N个数从小到大排序,对于每个数,要么不选它,要么将它与它的前一个数配对。动态转移方程:f[i][j]=min{f[i][j-1],f[i-1][j-2]+(L[j]-L[j-1])^2};
以下贴出代码:
1 #include <iostream> 2 #include <fstream> 3 using namespace std; 4 ifstream fin("P1125.in"); 5 ofstream fout("P1125.out"); 6 int N,K; 7 int length[101]; 8 int f[60][110]; 9 int kliner(int a,int b) 10 { 11 return a<=b?a:b; 12 } 13 int partion(int *a,int start,int end) 14 { 15 int i=0,j=start-1,t=0; 16 for(i=start;i<=end;i++) 17 { 18 if(a[i]<=a[end]) 19 { 20 j++; 21 t=a[i]; 22 a[i]=a[j]; 23 a[j]=t; 24 } 25 } 26 return j; 27 } 28 int quicksort(int *a,int start,int end) 29 { 30 if(start>=end) 31 return 0; 32 int j=partion(a,start,end); 33 quicksort(a,start,j-1); 34 quicksort(a,j+1,end); 35 return 0; 36 } 37 int main() 38 { 39 int i=0,j=0; 40 fin>>N>>K; 41 for(i=1;i<=N;i++) 42 { 43 fin>>length[i]; 44 } 45 if(N<2*K+6) 46 { 47 fout<<-1<<endl; 48 return 0; 49 } 50 quicksort(length,1,N); 51 for(i=1;i<=K+3;i++) 52 { 53 for(j=1;j<=N;j++) 54 { 55 if(j<2*i) 56 f[i][j]=99999999; 57 else 58 { 59 f[i][j]=kliner(f[i][j-1],f[i-1][j-2]+(length[j]-length[j-1])*(length[j]-length[j-1])); 60 } 61 } 62 } 63 fout<<f[K+3][N]<<endl; 64 return 0; 65 }
在动规前对题目中的各种性质进行仔细的发掘是一个OIer必要的素质,特别是将贪心与动规灵活的结合起来尤为重要。