5 6 2 8 7 1 0 5 2 10 20 0
10HintIn the sample, there is two ways to achieve Xiaoji‘s goal. [6 2 8 7 1] -> [8 8 7 1] -> [8 8 8] will cost 5 + 5 = 10. [6 2 8 7 1] -> [24] will cost 20.按照题目,我们可以发现左右端点不相等的时候,那么小的那个肯定要与邻近的数进行合并那么通过这个方法对整个数组来一次扫描,将其先合并成一个回文串,再统计各个部分合并了几个数,分别记为l区间和r区间然后再对l和r进行dp,统计将这个回文串再进行合并的各种情况下的最小花费最后枚举所有情况,找到最小值#include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> using namespace std; #define up(i,x,y) for(i=x;i<=y;i++) #define down(i,x,y) for(i=x;i>=y;i--) #define mem(a,b) memset(a,b,sizeof(a)) #define w(x) while(x) #define inf 99999999 #define l 5005 #define s(a) scanf("%d",&a) int dp[l],a[l],cost[l],lnum,rnum,lsum,rsum,len,i,j,ll[l],rr[l],ans,n; int main() { w((s(n),n)) { up(i,1,n) s(a[i]); up(i,1,n) s(cost[i]); len=0; for(i=1,j=n; i<j; i++,j--)//扫描,对整个串进行合并,成为回文 { lsum=a[i],rsum=a[j]; lnum=rnum=1; w(lsum!=rsum) { if(i>=j) break; if(lsum<rsum) { lsum+=a[++i]; lnum++; } else { rsum+=a[--j]; rnum++; } } if(lsum==rsum) { len++; ll[len]=lnum; rr[len]=rnum; } } up(i,1,len)//对两端进行DP { int t1=0,t2=0; dp[i]=inf; down(j,i,1) { t1+=ll[j]; t2+=rr[j]; dp[i]=min(dp[i],dp[j-1]+cost[t1]+cost[t2]); } } ans=cost[n]; up(i,1,len) { n-=ll[i]+rr[i];//中间部分进行合并 ans=min(ans,dp[i]+cost[n]); } printf("%d\n",ans); } return 0; }
HDU4960:Another OCD Patient,布布扣,bubuko.com
原文地址:http://blog.csdn.net/libin56842/article/details/38707365