NIOP1995 石子合并(区间DP)

状态转移方程在代码中标出

本题注意是圆形,所以之前要预先处理一下s数组。处理之后总长度为2*n-1.第一个合并的起点有n个,所以总的方案数是n

注释在代码中标出

http://www.rqnoj.cn/problem/490

 

石子合并问题推荐几篇很好的文章

http://blog.csdn.net/acdreamers/article/details/18039073

http://blog.csdn.net/bnmjmz/article/details/41308919

注意四边形不等式优化,可以把n^3优化到n^2

 

 1 //#pragma comment(linker, "/STACK:167772160")//手动扩栈~~~~hdu 用c++交
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<queue>
 7 #include<stack>
 8 #include<cmath>
 9 #include<set>
10 #include<algorithm>
11 #include<vector>
12 // #include<malloc.h>
13 using namespace std;
14 #define clc(a,b) memset(a,b,sizeof(a))
15 #define LL long long
16 const int Inf = 0x3f3f3f3f;
17 const double eps = 1e-5;
18 const double pi = acos(-1);
19 // inline int r(){
20 //     int x=0,f=1;char ch=getchar();
21 //     while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
22 //     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
23 //     return x*f;
24 // }
25 const int Times = 10;
26 const int N = 5500;
27 int s[210],d[210][210],p[210][210],a[210];//d/p表示i到j的最小/大花费
28 int main(){
29     int n;
30     int m;
31     s[0]=0;
32     while(~scanf("%d",&n)){
33         clc(d,0);
34         clc(p,0);
35         for(int i=1;i<=n;i++){
36             scanf("%d",&a[i]);
37             s[i]=s[i-1]+a[i];
38         }
39         for(int i=1;i<n;i++){
40             s[i+n]=s[n+i-1]+a[i];
41         }
42         m=n,n=n*2-1;
43         int j,tem1,tem2;
44         for(int r=2;r<=n;r++){//枚举i到j的长度
45             for(int i=1;i<=n-r+1;i++){//i起始坐标,j表示当前枚举的终点坐标
46                  j=i+r-1,tem1=Inf,tem2=0;
47                  for(int k=i;k<j;k++){
48                     tem1=min(tem1,d[i][k]+d[k+1][j]+s[j]-s[i-1]);
49                     tem2=max(tem2,p[i][k]+p[k+1][j]+s[j]-s[i-1]);
50                  }
51                  d[i][j]=tem1;
52                  p[i][j]=tem2;
53             }
54         }
55         tem1=Inf,tem2=0;
56         for(int i=1;i<=m;i++){//合并长度从1到m
57             if(tem1>d[i][m+i-1]) tem1=d[i][m+i-1];
58             if(tem2<p[i][m+i-1]) tem2=p[i][m+i-1];
59         }
60         if(n==1) tem1=tem2=a[1];
61         printf("%d\n%d\n",tem1,tem2);
62     }
63     return 0;
64 }
View Code

 

posted @ 2016-05-06 17:55  yyblues  阅读(217)  评论(0编辑  收藏  举报