题意:你是一个战士现在面对,一群狼,每只狼都有一定的主动攻击力和附带攻击力。你杀死一只狼。你会受到这只狼的(主动攻击力+旁边两只狼的附带攻击力)这么多伤害~现在问你如何选择杀狼的顺序使的杀完所有狼时, 自己受到的伤害最小。(提醒,狼杀死后就消失,身边原本相隔的两只狼会变成相邻,而且不需要考虑狼围城环这种情况)
题解:明显的区间DP,但是这题中需要自己确定一个 方案,不难想到先打2边在打中间;
子问题:在区间i,j上的代价;
划分:区间的直接合并的过程中,是区间和区间合并还是区间和点合并,即分割点是不是在边界;
总结:又是初始化,在dp问题的初始化上已经错了许多次了,写出转移方程后,一定要注意好边界情况以及 f 的第一项
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn=205; 7 const int INF=0x3f3f3f3f; 8 int f[maxn][maxn], a[maxn], b[maxn]; 9 10 int main() 11 { 12 //freopen("in.txt", "r", stdin); 13 int T, kase=0; cin>>T; 14 while(T--) 15 { 16 memset(a, 0, sizeof(a)); 17 memset(b, 0, sizeof(b)); 18 memset(f, 0, sizeof(f)); 19 //memset(f, 0x3f, sizeof(f)); 20 //这题的状态转移方程,有个f[i][k-1]和f[k+1][j] 21 int n; cin>>n; 22 for(int i=1; i<=n; i++) 23 cin>>a[i]; 24 for(int i=1; i<=n; i++) 25 cin>>b[i]; 26 27 memset(f, 0x3f, sizeof(f)); 28 for(int i=1; i<=n; i++) 29 f[i][i]=a[i]+b[i-1]+b[i+1]; //f的边界,这里不写也行,把len从0开始就可以了; 30 31 for(int len=1; len<n; len++) 32 for(int i=1; i<=n-len; i++) 33 { 34 int j=i+len; 35 for(int k=i; k<=j; k++) //k的范围要注意,是可以等于i和j的 36 { 37 if(k!=j&&k!=i) 38 f[i][j]=min(f[i][j], f[i][k-1]+a[k]+f[k+1][j]+b[i-1]+b[j+1]); 39 else if(k==j) 40 f[i][j]=min(f[i][j], f[i][k-1]+a[k]+b[i-1]+b[j+1]); 41 else 42 f[i][j]=min(f[i][j], a[k]+f[k+1][j]+b[i-1]+b[j+1]); 43 //以下的写法也可以AC,就是不判断k是否在端点, 不过这样写的话初始化就要好好注意一下了 44 //f[i][j]=min(f[i][j], f[i][k-1]+a[k]+f[k+1][j]+b[i-1]+b[j+1]); 45 } 46 } 47 printf("Case #%d: %d\n", ++kase, f[1][n]); 48 } 49 return 0; 50 }