区间动归

石子合并

链接

分析:dp[i][j]表示从i顺时针数j个位置的最大值,规划方向是顺推,初始时dp[i][i]=0。显然,我们需要求出合并个数为2,3,,,,n的情况,对于dp[i][j]我们假设最后一次合并位置为k,dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i,j],因为sum[i,j]表示i到j这段和,跟k取的位置无关,由此可以得到dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]),最大值同理

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 using namespace std;
 6 const int maxn=200+10;
 7 const int INF=1<<30;
 8 int f[maxn][maxn]; //max
 9 int dp[maxn][maxn]; //min
10 int sum[maxn],a[maxn];
11 int n;
12 int main()
13 {
14     cin>>n;
15     for(int i=1;i<=n;i++){
16         cin>>a[i];
17         sum[i]=sum[i-1]+a[i];
18     }
19     for(int i=n+1;i<=2*n;i++)
20         sum[i]=sum[n]+sum[i-n];
21     for(int i=1;i<=2*n;i++)
22         for(int j=1;j<=2*n;j++)
23             dp[i][j]=INF;
24     for(int i=1;i<=2*n;i++)  dp[i][i]=0;
25     for(int l=1;l<=n;l++){
26         for(int i=1;i<=2*n-l;i++){
27             int j=i+l;
28             for(int k=i;k<j;k++){
29                 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
30             }
31         }
32     }
33     memset(f,0,sizeof(f));
34     for(int l=1;l<=n;l++){
35         for(int i=1;i<=2*n-l;i++){
36             int j=i+l;
37             for(int k=i;k<j;k++){
38                 f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
39             }
40         }
41     }
42     int cnt=0,ans=INF;
43     for(int i=1;i<=n;i++)
44         cnt=max(f[i][i+n-1],cnt);
45     for(int i=1;i<=n;i++)
46         ans=min(dp[i][i+n-1],ans);
47     cout<<ans<<endl<<cnt<<endl;
48 }
View Code

 

能量项链

链接

分析:dp[i][j]表示i到j这段区间的最大值,我们需要枚举从哪个点切分,但是注意一个问题,对于一次获得能量,我们所需要用到的是a[i]和a[i+1]的值,所以可以得到状态转移方程dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(a[i]*a[k+1]*a[j+1]))

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 using namespace std;
 6 const int maxn=200+10;
 7 int a[maxn];
 8 int dp[maxn][maxn];
 9 int n;
10 int main()
11 {
12     cin>>n;
13     for(int i=1;i<=n;i++){
14         cin>>a[i];
15         a[i+n]=a[i];
16     }
17     for(int l=1;l<=n;l++){
18         for(int i=1;i<=2*n-l;i++){
19             int j=i+l;
20             for(int k=i;k<j;k++){
21                 dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(a[i]*a[k+1]*a[j+1]));
22             }
23         }
24     }
25     int cnt=0;
26     for(int i=1;i<=n;i++)
27         cnt=max(cnt,dp[i][i+n-1]);
28     cout<<cnt<<endl;
29 }
View Code

 

数字游戏

链接

分析:dp[i][j][z]表示区间[i,j]被分成z段的最大值,故dp[i][j][z]=max(dp[i][j][z],dp[i][k][z-1]*dp[k+1][j][1]),最小值同理

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 using namespace std;
 6 const int maxn=100+10;
 7 const int INF=1<<30;
 8 int n,m;
 9 int a[maxn],sum[maxn];
10 int dp[maxn][maxn][20];  //max
11 int f[maxn][maxn][20];  //min
12 int main()
13 {
14     cin>>n>>m;
15     for(int i=1;i<=n;i++){
16         cin>>a[i];
17         sum[i]=sum[i-1]+a[i];
18     }
19     for(int i=n+1;i<=2*n;i++)
20         sum[i]=sum[n]+sum[i-n];
21     memset(dp,0,sizeof(dp));
22     for(int i=1;i<=2*n;i++)
23         for(int j=1;j<=2*n;j++)
24             for(int z=1;z<=m;z++)
25                 f[i][j][z]=INF;
26     for(int i=1;i<=2*n;i++){
27         for(int j=1;j<=2*n;j++){
28             dp[i][j][1]=sum[j]-sum[i-1];
29             f[i][j][1]=sum[j]-sum[i-1];
30             while(dp[i][j][1]<0) dp[i][j][1]+=10;
31             dp[i][j][1]%=10;
32             while(f[i][j][1]<0)  f[i][j][1]+=10;
33             f[i][j][1]%=10;
34         }
35     }
36     for(int l=1;l<=n;l++){
37         for(int i=1;i<=2*n-l;i++){
38             int j=i+l;
39             for(int k=i;k<j;k++){
40                 for(int z=2;z<=m;z++)
41                     dp[i][j][z]=max(dp[i][j][z],dp[i][k][z-1]*dp[k+1][j][1]);
42             }
43         }
44     }
45     for(int i=1;i<=2*n;i++)
46         for(int z=2;z<=m;z++)
47             f[i][i][z]=0;
48     for(int l=1;l<=n;l++){
49         for(int i=1;i<=2*n-l;i++){
50             int j=i+l;
51             for(int k=i;k<j;k++){
52                 for(int z=2;z<=m;z++)
53                     f[i][j][z]=min(f[i][j][z],f[i][k][z-1]*f[k+1][j][1]);
54             }
55         }
56     }
57     int cnt=0,ans=INF;
58     for(int i=1;i<=n;i++)
59         cnt=max(dp[i][i+n-1][m],cnt);
60     for(int i=1;i<=n;i++)
61         ans=min(f[i][i+n-1][m],ans);
62     cout<<ans<<endl<<cnt<<endl;
63 }
View Code
posted @ 2017-07-17 01:46  wolf940509  阅读(192)  评论(0编辑  收藏  举报