石子合并动态规划

在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。    

编一程序,由文件读入堆数N及每堆的石子数(≤20),      

①     选择一种合并石子的方案,使得做N-1次合并,得分的总和最小;      

②     选择一种合并石子的方案,使得做N-1次合并,得分的总和最大。    

例如,所示的4堆石子,每堆石子数(从最上面的一堆数起,顺时针数)依次为4 5 9 4。则3次合并得分总和最小的方案:8+13+22=43得分最大的方案为:22+18+22=54

 

解题思路:

根据题意来拟定状态,dp[i][j]从i到j堆石子合并所得总分最大或者最小。

利用分治的思想我们就可以看得出来,我们首先将每相邻的两堆石子合并得到一个得分,然后再扩展到3堆石子合并,3堆由两堆石子的合并情况推出,这样便形成了一种递推的效果,n堆自然能够推断到,只是注意,本题是围绕操场所以最后的石子与起始石子相邻。

View Code
 1 #include<iostream>
 2 const int  N = 102;
 3 using namespace std;
 4 int sum[N*2][N*2],tt[N*2][N*2],n; 
 5 int main()
 6 {
 7     while(scanf("%d",&n)!=EOF)
 8     {
 9            memset(sum,0,sizeof(sum));
10            for(int i=1;i<=n;i++)
11                scanf("%d",&sum[i][i]);
12            for(int i=n+1;i<2*n;i++)sum[i][i]=sum[i-n][i-n];
13            for(int i=1;i<2*n;i++)
14            {
15                for(int j=i+1;j<2*n;j++)
16                {
17                    sum[i][j]+=sum[i][j-1]+sum[j][j]; 
18                }
19            }
20           for(int i=1;i<2*n;i++)
21               for(int j=1;j<2*n;j++)
22                  if(i==j)
23                  tt[i][j]=0;
24                  else
25                  tt[i][j]=100000000;
26           for(int i=2;i<=n;i++)
27                for(int j=1;j<2*n-i+1;j++)
28                {
29                    for(int k=j;k<j+i-1;k++)
30                    {        
31                        tt[j][j+i-1]=min(tt[j][k]+tt[k+1][j+i-1]+sum[j][j+i-1],tt[j][j+i-1]);
32                    }
33                }
34           int mi=0x7fffffff;
35           for(int i=1;i<=n;i++)
36               if(tt[i][i+n-1]<mi)mi=tt[i][i+n-1];
37           printf("%d\n",mi);
38           memset(tt,0,sizeof(tt));
39           for(int i=2;i<=n;i++)
40                for(int j=1;j<2*n-i+1;j++)
41                {
42                    for(int k=j;k<j+i-1;k++)
43                    {        
44                        tt[j][j+i-1]=max(tt[j][k]+tt[k+1][j+i-1]+sum[j][j+i-1],tt[j][j+i-1]);
45                    }
46                }
47           mi=0;
48           for(int i=1;i<=n;i++)
49              if(tt[i][i+n-1]>mi)mi=tt[i][i+n-1];
50           printf("%d\n",mi);
51     }
52     return 0;    
53 }

 

posted @ 2012-10-22 21:05  诺小J  阅读(409)  评论(0编辑  收藏  举报