石子合并+环形石子合并(区间DP,环形转换为链形)

传送门:石子合并

 传送门:环形石子合并

思路:状态表示:f[i][j]表示在i~j这段区间内所能取得的最小值

           状态转移方程:f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+d[j]-d[i-1]

            i~j的值可以由i~k,k+1~j这两段的值加上它们合并时的产生和得来,枚举取得最小值。

时间复杂度为O(n^3)

代码1:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<sstream>
using namespace std;
typedef long long LL;
const int N=310;
int n,a[N],dp[N][N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
{
        cin>>a[i];
a[i]+=a[i-1];
}
    for(int len=2;len<=n;len++)
        for(int i=1;i+len-1<=n;i++)
    {
        int l=i,r=i+len-1;
        dp[l][r]=1e9;
        for(int k=l;k<r;k++)
            dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+a[r]-a[l-1]);
    }
    cout<<dp[1][n]<<endl;
    return 0;
}

代码2:

思路:将n个数扩充为2*n个数,环状问题转化成链状问题。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
const int N=420;
int f[N][N],g[N][N];
int d[N],a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++)
        d[i]+=d[i-1]+a[i];
    memset(f,0x3f,sizeof f);
    memset(g,-0x3f,sizeof g);


    for(int len=1;len<=n;len++)
    for(int l=1;l+len-1<=2*n;l++)
    {
        int r=l+len-1;
        if(len==1)
            f[l][r]=g[l][r]=0;
        else
        for(int k=1;k<r;k++)
        {
            f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+d[r]-d[l-1]);
            g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]+d[r]-d[l-1]);
        }
    }
    int sum=1e9;
    int sum1=-1e9;
    for(int i=1;i<=n;i++)
    {

        sum=min(sum,f[i][i+n-1]);
         sum1=max(sum1,g[i][i+n-1]);
    }
    cout<<sum<<endl;
    cout<<sum1<<endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值