CSU 1592 石子归并 相邻操作Dp问题

来源:互联网 发布:软件项目质量保证措施 编辑:程序博客网 时间:2024/06/06 03:10

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1592

题意:给定一堆石子,每次只能合并相邻两堆,每次的合并代价为两者石子数之和,求最后只剩下一堆时的最小合并代价。

刚开始,想到的是贪心,每次合并相邻和值最小的两堆就行了,这题和 POJ 3186  Treats for the Cows以及紫书上的“最优矩阵链乘”差不多,初看看似贪心,实则是Dp问题,但是都不会,呵呵。。。。只能看别人的代码,然后再写。。。

思路:用dp[i][j]表示合并区间[i,j]所需要的最小代价,那么,状态转移方程为:dp[i][j]=max(dp[i]k]+dp[k+1][j]+sum[i][j]),i<=k<=j。显然,对于我来讲,这个式子是不好直接实现递推的,但是发现这个递推式子和紫书上的最优矩阵链乘差不多,都表示:要求大区间的解,得先知道小区间的解,所以,可以把上述状态进行转换一下:用dp[i][j]表示,以i为起点,长度为j的解,则状态转移方程变为:dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k+1][j-k-1]+sum[i][i+j]);这样一来,就好实现递推方程了。


代码:

#include<iostream>#include<cstdio>#define maxn 110#define INF 0x7fffffffusing namespace std;int N,A[maxn],dp[maxn][maxn],sum[maxn];int main(){    //freopen("in.txt","r",stdin);    int T;cin>>T;    while(T--){        cin>>N;        for(int i=1;i<=N;i++)            scanf("%d",A+i);        sum[0]=0;        for(int i=1;i<=N;i++)            sum[i]=sum[i-1]+A[i];        for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) dp[i][j]=INF;//初始化        for(int i=1;i<=N;i++) dp[i][0]=0;//初始化        for(int j=1;j<N;j++) for(int i=1;i+j<=N;i++)//先枚举长度j            for(int k=0;k<j;k++)                dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k+1][j-k-1]+sum[i+j]-sum[i-1]);        cout<<dp[1][N-1]<<endl;    }    return 0;}


0 0
原创粉丝点击