上次北京赛现场赛的题了,昨天做了道区间dp,突然想起来这道题,都是很类似的,就翻出来做了做
刚开始像昨天做的那道一样,老想着怎么逆推,后来发现这道题应该正着推
其实正推和逆推乍看起来是很相似的,只不过一个是dp[i][j]表示i、j左右还有其他狼时消灭掉i-j这段消耗的费用,一个是表示最后只剩i-j时消灭掉这段的费用
总结一下昨天那道区间dp和今天的区间dp的相同点,发现区间dp适用于费用会随着时间的推移,或者说dp的进行不断变化
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int inf=999999999; int a[205],b[205]; int dp[205][205],n; void init(){ for(int i=0;i<205;i++){ for(int j=0;j<205;j++){ dp[i][j]=inf; } } b[n+1]=0; for(int i=1;i<=n;i++) dp[i][i]=a[i]+b[i-1]+b[i+1]; for(int i=1;i<n;i++) dp[i][i+1]=min(dp[i][i]+a[i+1]+b[i+2]+b[i-1],dp[i+1][i+1]+a[i]+b[i-1]+b[i+2]); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T; scanf("%d",&T); int cas=1; while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { scanf("%d",&b[i]); } init(); for(int l=3;l<=n;l++){ for(int i=1;i+l-1<=n;i++){ int j=i+l-1; dp[i][j]=min(dp[i][j],dp[i+1][j]+a[i]+b[i-1]+b[j+1]); dp[i][j]=min(dp[i][j],dp[i][j-1]+a[j]+b[j+1]+b[i-1]); for(int k=i+1;k<=j-1;k++){ dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+b[i-1]+b[j+1]+a[k]); } //printf("dp[%d][%d] :%d\n",i,j,dp[i][j]); } } printf("Case #%d: %d\n",cas++,dp[1][n]); } }
时间: 2024-12-11 15:07:46