代码改变世界

tyvj P1125题解

2012-10-16 20:14  kliner  阅读(216)  评论(0编辑  收藏  举报

  题目大意:第一行输入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必要的素质,特别是将贪心与动规灵活的结合起来尤为重要。