十字合并(DP)2018-08-10

一道经典的题:https://www.luogu.org/problemnew/show/P1090
这道题虽然比普通的要多考虑一点,因为有环形,但我们仍然可以通过非环形的例子来做一下,再来做这道题。
分析:这道题如果用贪心的思路当然也可以,只需要每次都选择最小的两个数相加就可以了,这里就不附上代码了QAQ
非环形代码:这里需要做一个预处理,也就是计算一个前缀和,然后DP一下,当前如果是合并前两个还是后两个,代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2000+10;
int a[maxn],f[maxn][maxn],sum[maxn];
int main(){
    int i,j,k,n,m;
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=1000000;
    for(int i=1;i<=n;i++){
        cin>>a[i];
            f[i][i]=0;
             sum[i]=sum[i-1]+a[i];
    }
    for(int len=1;len<n;len++)
        for(int i=1;i<n;i++){
            int j=i+len;
            if(j>n)
              j=n;
             for(int k=i;k<j;k++)
              f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
        }
    cout<<f[1][n];
    return 0;

}

做完了非环形代码,现在我们就能来做一下环形的代码了!!!
环形代码:如果是首尾相连,我们就可以在后面接上一段,保证转移方程可以继续正常运行,这样我们的程序也需要做一些改动:

#include <bits/stdc++.h>
using namespace std;
const int maxn=200+10;
int a[maxn],f[maxn][maxn],sum[maxn];
int main(){
    int i,j,k,n,m;
    cin>>n;
    for(int i=1;i<=n*2;i++)
        for(int j=1;j<=n*2;j++)
            f[i][j]=1000000;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++){
        f[i][i]=0;
        sum[i]=sum[i-1]+a[i];
    }
    for(int len=1;len<n;len++)
        for(int i=1;i<2*n;i++){
            int j=i+len;
            if(j>2*n)
               j=2*n;
            for(int k=i;k<j;k++)
               f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
        }
    int ans=100000;
    for(int i=1;i<=n;i++)
        ans=min(ans,f[i][i+n-1]);
    cout<<ans;
    return 0;

}

做完这道题,我们就可以挑战BOSS了!!!
https://www.luogu.org/problemnew/show/P1880
这一道题显然在环形上增加了最大值,以前求得是最小值,所以这样代码就可以构造出来了:

#include <bits/stdc++.h>
using namespace std;
const int maxn=200+10;
int a[maxn],f[maxn][maxn],sum[maxn],f1[maxn][maxn];
int main(){
    int i,j,k,n,m;
    cin>>n;
    for(int i=1;i<=n*2;i++)
        for(int j=1;j<=n*2;j++){
            f[i][j]=1000000;
            f1[i][j]=-1000000;
         }
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++){
        f[i][i]=0;
        f1[i][i]=0;
        sum[i]=sum[i-1]+a[i];
    }
    for(int len=1;len<n;len++)
        for(int i=1;i<2*n;i++){
            int j=i+len;
            if(j>2*n)
               j=2*n;
            for(int k=i;k<j;k++)
               f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
        }
      for(int len=1;len<n;len++)
        for(int i=1;i<2*n;i++){
            int j=i+len;
            if(j>2*n)
               j=2*n;
            for(int k=i;k<j;k++)
               f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
        }
    int ans=100000;
    for(int i=1;i<=n;i++)
        ans=min(ans,f[i][i+n-1]);
    cout<<ans;
    int ans1=-100000;
    for(int i=1;i<=n;i++)
        ans1=max(ans1,f1[i][i+n-1]);
    cout<<endl<<ans1;
    return 0;

}

猜你喜欢

转载自blog.csdn.net/qq_42875611/article/details/81570089