zoukankan      html  css  js  c++  java
  • I-country

    I-country

    (n imes m)的网格图中,给出每个格子的权值,寻找有k个格子的凸联通块,使包含的权值最大,(N,M≤15,K≤225)

    我们首先要知道凸联通块的定义

    1. 从任意一个位置到任意一个位置的路径中存在一条行走方向只有两个。
    2. 左右轮廓分别先递减后递增,先递增后递减。

    显然定义1不能用来递推,考虑性质2,而且从考虑行列角度,我们要表现处理到哪一行,格子的选择有限制,要表现格子的选择,要表现轮廓单调性,我们要设当前想要表现哪种单调性,所以同时需要此行选择的列范围,判断单调性的合法,于是设(w[i][j])表示第i行的前缀和,同时设(f[i][j][k][l][0/1][0/1])表示处理到第i行,已选了j个格子,该行选第k列到第l列,0/1从左至右表示,左边和右边的是否递增(1表示递增,反之),于是有

    [f[i][j][k][l][0][0]=max_{kleq p,lleq qleq m}(f[i][j-(l-k+1)][p][q][0][0/1])+w[i][l]-w[i][k-1] ]

    [f[i][j][k][l][0][1]=max_{kleq pleq qleq l}(f[i][j-(l-k+1)][p][q][0][1])+w[i][l]-w[i][k-1] ]

    [f[i][j][k][l][1][0]=max_{1leq pleq k,lleq qleq m}(f[i][j-(l-k+1)][p][q][0/1][0/1])+w[i][l]-w[i][k-1] ]

    [f[i][j][k][l][1][1]=max_{1leq pleq kleq qleq l}(f[i][j-(l-k+1)][p][q][0/1][1])+w[i][l]-w[i][k-1] ]

    边界:全部负无限大,特判此状态不与前面后接

    答案:(max_{1leq pleq qleq m}(f[n][m][p][q][1][0]))

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define intmax 0x7fffffff
    using namespace std;
    struct DP{
        int i,l,r,d;DP* pre;
        DP(){d=-intmax;}
    }dp[16][256][16][16][2][2],ans;
    int s[16][16];
    template<class free>
    il void cmp(free&,free&);
    il void read(int&),print(DP*);
    int main(){
        int n,m,g;
        read(n),read(m),read(g);
        if(!g)return puts("Oil : 0"),0;
        for(int i(1),j;i<=n;++i)
            for(j=1;j<=m;++j)read(s[i][j]),s[i][j]+=s[i][j-1];
        for(int i(1),j,k,l,p,q;i<=n;++i)
            for(j=1;j<=g;++j)
                for(k=1;k<=m;++k)
                    for(l=k;l<=m;++l){
                        if(j-(l-k+1)<0)continue;
                        //0 0
                        DP*x(&dp[i][j][k][l][0][0]);
                        for(p=k;p<=l;++p)
                            for(q=l;q<=m;++q)
                                cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][0]),
                                    cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][1]);
                        if(x->d<0&&l-k+1==j)x->d=0,x->pre=NULL;
                        x->d+=s[i][l]-s[i][k-1],x->l=k,x->r=l,x->i=i;
                        //0 1
                        x=&dp[i][j][k][l][0][1];
                        for(p=k;p<=l;++p)
                            for(q=p;q<=l;++q)
                                cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][1]);
                        if(x->d<0&&l-k+1==j)x->d=0,x->pre=NULL;
                        x->d+=s[i][l]-s[i][k-1],x->l=k,x->r=l,x->i=i;
                        //1 0
                        x=&dp[i][j][k][l][1][0];
                        for(p=1;p<=k;++p)
                            for(q=l;q<=m;++q)
                                cmp(*x,dp[i-1][j-(l-k+1)][p][q][1][0]),
                                    cmp(*x,dp[i-1][j-(l-k+1)][p][q][1][1]),
                                    cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][0]),
                                    cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][1]);
                        if(x->d<0&&l-k+1==j)x->d=0,x->pre=NULL;
                        x->d+=s[i][l]-s[i][k-1],x->l=k,x->r=l,x->i=i;
                        //1 1
                        x=&dp[i][j][k][l][1][1];
                        for(p=1;p<=k;++p)
                            for(q=k;q<=l;++q)
                                cmp(*x,dp[i-1][j-(l-k+1)][p][q][1][1]),
                                    cmp(*x,dp[i-1][j-(l-k+1)][p][q][0][1]);
                        if(x->d<0&&l-k+1==j)x->d=0,x->pre=NULL;
                        x->d+=s[i][l]-s[i][k-1],x->l=k,x->r=l,x->i=i;
                    }
        for(int i(1),j,k,l,x,y;i<=n;++i)
            for(k=1;k<=m;++k)
                for(l=1;l<=m;++l)
                    for(x=0;x<2;++x)
                        for(y=0;y<2;++y)
                            if(dp[i][g][k][l][x][y].d>ans.d)
                                ans=dp[i][g][k][l][x][y];
        printf("Oil : %d
    ",ans.d),print(&ans);
        return 0;
    }
    il void print(DP *x){
        int i;
        while(x!=NULL){
            for(i=x->l;i<=x->r;++i)
                printf("%d %d
    ",x->i,i);
            x=x->pre;
        }
    }
    template<class free>
    il void cmp(free &a,free &b){
        if(a.d<b.d)a.d=b.d,a.pre=&b;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
  • 相关阅读:
    day25 初始面向对象
    JavaScript中的apply()和call()
    JavaScript中的arguments详解
    测试使用MarkDown在博客园发布博客
    《Spring实战》 1-2
    总结: 《jQuery基础教程》 5-完结
    总结: 《jQuery基础教程》 1-4章
    做个计划
    Nginx与tomcat组合的简单使用
    利用 Dijit 组件框架打造丰富的用户界面
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10905282.html
Copyright © 2011-2022 走看看