这题是区间DP。看见dp就成傻逼了。
题目的意思是ai表示每头狼的本身具备的攻击力,bi表示能提供给相邻狼的攻击力,以什么样的顺序去杀狼可以使狼对人的攻击最少。
且如果狼被杀了,就不能为相邻的狼提供攻击力了。
动态转移方程为dp[i][j]=min(dp[i][k]+dp[k][j]+a[k]+a[i]+a[j],dp[i][j])(j<k<i);
i表示以第i头狼为右端点(还未斩杀),j表示以第j头狼为左端点(还未斩杀)。
dp[i][j]记录的为以i,j未选时,那个而i-j内的点已选好的最小的攻击。
(这道题做的我。。。。花了差不多一天时间,中间想想发发呆,就这种状态。还是懒,,,,然而现在还没有想的太明白。。。。。。。。)。
首先a,b数组两端要多加一位,a[0]=0;b[0]=0;a[p+1]=0;b[p+1]=0;
因为要把所有的狼都杀完,因为每次都要有两端,所以要杀完就必须是0-p+1内的编号1到p的狼,1左,p右端必须要有个端点。最后答案就是dp[p+1][0];
从后往前说dp比较好理解,dp[p+1][0]为最后一个状态,那么要最优就看最后选走的是哪一个,那么可以得到,dp[p+1][0]=min(dp[p+1][k]+dp[k][0]+a[k]+b[p+1]+b[0]);
这里面的k就是最后取走的,在求就要求dp[p+1][k]的最优,这个以p+1为左端以k为右端,当然还是这个状态转移方程,同理求dp[k][0];
然后反着推理解了,就从正着来写成递推。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<stdlib.h> 5 #include<string.h> 6 using namespace std; 7 long long N=1e16; 8 typedef long long ll; 9 int main(void) 10 { 11 int i,j,k,p,q; 12 ll dp[300][300]; 13 ll a[300]; 14 ll b[300]; 15 scanf("%d",&k); 16 for(i=1; i<=k; i++) 17 { 18 scanf("%d",&p); 19 memset(a,0,sizeof(a)); 20 memset(b,0,sizeof(b)); 21 memset(dp,0,sizeof(dp)); 22 for(j=1; j<=p; j++) 23 scanf("%lld",&a[j]); 24 for(j=1; j<=p; j++) 25 scanf("%lld",&b[j]); 26 int n,m,t; 27 for(n=2; n<=p+1; n++)//首位是0,因为至少需要3个数才能有两个端点,中间有数,所以从二开始,dp[i][j](i-j<3价值都为0) 28 { 29 for(m=n-2; m>=0; m--) 30 { 31 dp[n][m]=dp[n][n-1]+dp[n-1][m]+a[n-1]+b[n]+b[m]; 32 for(t=n-1; t>m; t--)//找最优的断点 33 { 34 dp[n][m]=min(dp[n][t]+dp[t][m]+b[n]+a[t]+b[m],dp[n][m]); 35 } 36 } 37 } 38 printf("Case #%d: %lld ",i,dp[p+1][0]); 39 } 40 return 0; 41 }