zoukankan      html  css  js  c++  java
  • 洛谷P1880 石子合并

    此题是基于单纯线性的石子合并(单纯的石子合并https://vjudge.net/problem/51Nod-1021)基础上进行了修改,增加了环形这一条件。

    我们先忽略掉环形首先从单纯线性合并做起,我们写出这样一个DP方程式dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+d(i,j)),

    dp[i][j]表示从i合并到j的最小值,我们分别求得每个区间的最小,最后进行合并,最终的最大值一定是最小的,容易反证证明。

    那么我们以k作为一个分界线例如,我要合并1~5的数字,那么我就有1~1 & 2~5   1~2 & 3~5   1~3 & 4~5  1~4 & 5~5 这几种选择再加上1~5的前缀和,那么我们就可以解决这一问题,接下来我们考虑如何去解决环形这一问题 我们注意到例如1 2 3 4可以变为 2 3 4 1 、3 4 1 2 、4 1 2 3 于是我们可以将这个数字串扩为2倍,并不断去算不同排列下的最优解,这样我们就解决了这一问题。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int a[201];
    int dpmax[202][202],d[201],dpmin[202][202];
    int cal(int i,int j) {return d[j] - d[i-1];}
    int main() {
        int n;
        cin>>n;
        for(int i=1; i<=n; i++) {
            cin>>a[i];
            d[i] = d[i-1] + a[i];
            a[i+n] = a[i];    
        }
        for(int i=n+1; i<=n*2; i++) {
            d[i] = d[i-1] + a[i];
        }
        for(int len=1; len<=n-1; len++) {
            for(int i=1,j=i+len; (i<n*2)&&(j<n*2); i++,j=i+len) {
                dpmin[i][j] = 99999999;
                for(int k=i; k<j; k++) {
                    dpmax[i][j] = max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]+cal(i,j));
                    dpmin[i][j] = min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]+cal(i,j));
                }
            }
        }
        int ans1=-1,ans2=99999999;
        for(int i=1; i<=n; i++){
            ans1 = max(ans1,dpmax[i][i+n-1]);
            ans2 = min(ans2,dpmin[i][i+n-1]);
        }
        cout<<ans2<<endl<<ans1;
        return 0;
    }
    总体观察下来,我们发现区间DP有点像分治

    但是此题的复杂度为O(n^3) 因此我们采用平行四边形不等式进行优化,使最终复杂度为O(n^2);

    首先我们给出如下定义:

    1.如果函数w满足:
    w[a,c] + w[b,c] leq w[b,c]+w[a,d](a<b<c<d)
    则w满足四边形不等式(简称w为凸)

    2.如果函数w满足:
    w[i,j]<=w[i'][j'] ([i,j]包含于[i',j'])
    则说w关于区间包含关系单调
     
    四边形不等式优化:1.对于一个函数w,如果a<=b<=c<=d,函数w有w(a,c)+w(c,d)<=w(a,d)+w(b,c),即交叉小于包含,我们就说函数w满足四边形不等式
    2.对于另一个函数m,如果有m(i,j)=min{m(i,k−1),m(k,j)}+w(i,j)(i≤k≤j),且w具有区间包含单调性我们就说m也满足四边形不等式,
    3.假如m满足四边形不等式,那么s(i,j)单调
    即s(i,j)≤s(i,j+1)≤s(i+1,j+1),s是记录m函数最优时下标的位置。
    我们在此只是利用其中的结论。注意,同时注意这里的m取得必须是min,对于max并不满足上述内容,但对于max又有另一个结论,我们直接给出
     
    即  使最大值最优的决策P[i][j]要么是i,要么是j−1
    因此我们可以使用这一优化,让每次的分界线决策在一个常数内,因此整个算法的复杂度为O(n^2);
    第一重循环控制长度,第二重循环控制DP位置,第三重循环控制每次循环时的分界线->第三重循环控制从s[i][j-1]~s[i+1][j]选择分界线
    既然我们进行了优化,那么就要像01背包那样仔细去考虑如何去循环
    第一重循环我们从后向前遍历 因为我们需要s[i+1][j];
    第二重循环我么从前向后遍历 因为我们需要s[i][j-1];
    关于上述内容的证明可以参考  (https://www.cnblogs.com/ybwowen/p/11116654.html)
     
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    int dp[maxn][maxn];
    int dp2[maxn][maxn];
    int n;
    int a[maxn];
    int sum[maxn];
    int p[maxn][maxn];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i];
        for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i],p[i][i]=i;
        for(int i=n<<1;i>=1;i--)
            for(int j=i+1;j<=n<<1;j++){
                dp[i][j]=0x3f3f3f3f;
                dp2[i][j]=max(dp2[i][i]+dp2[i+1][j],dp2[i][j-1]+dp2[j][j])+sum[j]-sum[i-1];
                for(int k=p[i][j-1];k<=p[i+1][j];k++)
                    if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]<dp[i][j]){
                        dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
                        p[i][j]=k;
                    }else if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]==dp[i][j])
                        p[i][j]=max(p[i][j],k);
                
            }
        int ans=0x3f3f3f3f;
        int ans2=0;
        for(int i=1;i<=n;i++) ans=min(ans,dp[i][i+n-1]);
        for(int i=1;i<=n;i++) ans2=max(ans2,dp2[i][i+n-1]); 
        printf("%d
    %d
    ",ans,ans2);
        return 0;
    }
     
     
    另外的一些关于四边形优化的知识可参考https://www.jianshu.com/p/3a5b7d8e007f
  • 相关阅读:
    Oracle存储过程 一个具体实例
    quartz定时格式配置以及JS验证
    day10_多进程、协程
    day10_锁、守护进程
    day10_单线程和多线程下载文件
    day10_多线程把六个网站写到文件里
    day10_主线程等待子线程的两种方式
    day10_修改父类的构造方法(不重要)和鸭子类型
    day10_hasattr和getattr、setattr、delattr和property的用法
    pycharm professional2019.1破解过程
  • 原文地址:https://www.cnblogs.com/delta-cnc/p/12353444.html
Copyright © 2011-2022 走看看