和1055沙子合并类似
环形石子合并,还是区间DP
这里需要求两个,一个是最小总代价,一个是最大总代价,两个只需要把min和max改一下其他一模一样。
以最小代价为例:
dp[i][j]表示合并从i到j的石子所需要的最小总代价,这里和线段石子合并不同的是,可以循环,说白了就是j可以大于n,这种环形的东西,一直让我感到很麻烦,但也没能想出很好的办法,所以就分两种情况判断了一下,就j<=n和j>n,前者和之前一样没有任何区别,后者for(int k = i;k<j;++k)这里可以直接循环,在循环体内的时候j和k要 %n。。我曾尝试把前面那两个对j的判断合并,但是由于j%n==0一直不知道这里怎么办,后来就放弃了。
仔细想一下,自己举两个例子再把大脑当成CPU手动运行一下就很好理解了。。。最后求得的dp[i][j]中取区间为n(即dp[1][n]、dp[2][1]、dp[3][2]、dp[4][3]....dp[n][n-1])当中的最小值。
其实只要理解了直线型的石子合并,这题主要的想法就已经不在DP上了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define INF 11111111 6 #define maxn 105 7 using namespace std; 8 int dp[maxn][maxn],d[maxn][maxn],sum[maxn]; 9 int main() 10 { 11 int n,m; 12 while(cin>>n>>m) 13 { 14 sum[0] = 0; 15 for(int i = 1;i<=n;++i) 16 { 17 int t; 18 scanf("%d",&t); 19 sum[i] = sum[i-1]+t; 20 } 21 for(int i = 1;i<=n;++i) 22 for(int j = 1;j<=n;++j) 23 { 24 dp[i][j]=(i==j?0:INF); 25 d[i][j]=(i==j?0:-1); 26 } 27 for(int r = 2;r<=n;++r) 28 for(int i = 1;i<=n;++i) 29 { 30 int j = i+r-1; 31 if(j<=n) 32 { 33 for(int k = i;k<j;++k) 34 { 35 dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]); 36 d[i][j] = max(d[i][j],d[i][k]+d[k+1][j]); 37 } 38 dp[i][j]+=(sum[j]-sum[i-1]); 39 d[i][j]+=(sum[j]-sum[i-1]); 40 } 41 else 42 { 43 for(int k = i;k<=j;++k) 44 { 45 dp[i][j%n] = min(dp[i][j%n],dp[i][k%n]+dp[(k+1)%n][j%n]); 46 d[i][j%n] = max(d[i][j%n],d[i][k%n]+d[(k+1)%n][j%n]); 47 } 48 dp[i][j]+=(sum[n]+sum[j]-sum[i-1]); 49 d[i][j]+=(sum[n]+sum[j]-sum[i-1]); 50 } 51 } 52 int mmin = dp[1][n]; 53 int mmax = d[1][n]; 54 55 for(int i = 2;i<=n;++i) 56 { 57 mmin = min(mmin,dp[i][(i+n-1)%n]); 58 mmax = max(mmax,d[i][(i+n-1)%n]); 59 } 60 if(m>mmax)printf("It is easy\n"); 61 else if(m<mmin)printf("I am..Sha...X\n"); 62 else printf("I will go to play WarIII\n"); 63 } 64 return 0; 65 }
时间: 2024-12-16 13:07:22