题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5115
题目分类:区间dp
题意:有n只狼,每只狼有两种属性,一种攻击力一种附加值,我们没杀一只狼,那么我们受到的伤害值为这只狼的攻击值与它旁边的两只狼的附加值的和,求把所有狼都杀光受到的最小的伤害值。
题目分析:
dp[i][j]表示把区间i,j内的所有狼杀光所受到的最小的伤害。
状态转移方程为
dp[i][j]=min{dp[i][k]+dp[k+1][j]-b[k]+b[i+1],
dp[i][k]+dp[k+1][j]-b[k+1]+b[j+1]}(i<=k<j)
先确定长度,然后再确定ij,否则是不对的
代码:
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f /**赤裸裸的区间DP dp[i][j]表示把区间i,j内的所有狼杀光所受到的最小的伤害。 状态转移方程为 dp[i][j]=min{dp[i][k]+dp[k+1][j]-b[k]+b[i+1], dp[i][k]+dp[k+1][j]-b[k+1]+b[j+1]}(i<=k<j) 这里讨论了先杀左边的还是先杀右边的处理的时候要注意a[0],b[0],a[n+1],b[n+1]的初值都是0.*/ int t,n; int a[500]; int b[500]; int dp[500][500]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif scanf("%d",&t); for(int kase=1;kase<=t;kase++) { scanf("%d",&n); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { scanf("%d",&b[i]); } memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { dp[i][i]=a[i]+b[i-1]+b[i+1]; //printf("%d ",dp[i][i]); } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { dp[i][j]=INF; } } // memset(dp,0,sizeof(dp)); for(int len=1;len<=n;len++) { for(int i=1;i+len<=n;i++) { int j=i+len; for(int k=i;k<j;k++) { dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]-b[k]+b[i-1]); dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]-b[k+1]+b[j+1]); } } } printf("Case #%d: ",kase); printf("%d ",dp[1][n]); } return 0; }