经典问题石子合并(环形)DP

来源:互联网 发布:tableview性能优化 编辑:程序博客网 时间:2024/05/22 03:19
区间DP,合并石子问题,区别就是PPT中是线性的
定义状态DP[i][j]表示从i到j合并金币的最小质量和
那么状态转移方程就是dp[l][i]+dp[i+1][r]+sum(l,r);(l<=i<r)
而该题目是环形的,解决的办法是将长度变为二倍那么直接每次DP(i,i+N-1)就可以模拟成环形

求出最小值就可以

#include <map>#include <set>#include <list>#include <cmath>#include<cctype>#include <ctime>#include <deque>#include <stack>#include <queue>#include <cstdio>#include <string>#include <vector>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#define LL long long#define PI 3.1415926535897932626using namespace std;int gcd(int a, int b){return a % b == 0 ? b : gcd(b, a % b);}LL dp[210][210];LL sum[210];int weight[210];int N;LL get_sum(int l, int r){    return sum[r]-sum[l]+weight[l];}LL DP(int l, int r){    LL &ans=dp[l][r];    if (ans!=-1) return ans;    if (l==r) return ans=0;    if (l<=N && r<=N) return ans=DP(l+N,r+N);    ans=1e14;    LL tmp=get_sum(l,r);    for (int i=l;i<r;i++)    {        ans=min(ans,DP(l,i)+DP(i+1,r)+tmp);    }    return ans;}int main(){    while (scanf("%d",&N)!=EOF)    {        memset(sum,0,sizeof(sum));        for (int i=1;i<=N;i++)        {            scanf("%d",&weight[i]);            weight[i+N]=weight[i];        }        sum[1]=weight[1];        for (int i=2;i<=N*2;i++)sum[i]=sum[i-1]+weight[i];        memset(dp,-1,sizeof(dp));        for (int i=1;i<=2*N;i++)            printf("%lld ",sum[i]);        putchar('\n');          for (int i=1;i<=2*N;i++)            printf("%d ",weight[i]);        putchar('\n');        LL ans=1e14;        for (int i=1;i<=N;i++)        {            ans=min(ans,DP(i,i+N-1));        }        printf("%lld\n",ans);    }    return 0;}


0 0
原创粉丝点击