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

    题目描述

    在 N*M 的矩阵中,每个格子有一个权值,要求寻找一个包含 K 个格子的凸连通块(连通块中间没有空缺,并且轮廓是凸的,如右图所示),使这个连通块中的格子的权值和最大。求出这个最大的权值和.N,M≤15,K≤225。

    输入格式

    第一行给出N,M,K,接下来给出这个矩阵

    输出格式

    如题


    首先我们要明确凸连通块是什么:

    它是一个连通块。从上往下看,它的左端点下标先递减后递增,右端点下标先递增后递减。

    根据这一点,我们能够设计出这样的状态:

    设dp(i,j,l,r,0/1,0/1)表示当前为第i行,已经用了j个格子,凸连通块在第i行的左端点为l,右端点为r,左端点现在在递增(0)还是递减(1),右端点在递增(0)还是递减(1)。那么可以列出状态转移方程:

    [len=r-l+1\ dp[i][j][l][r][1][0]=sum_{p=l}^{r}a[i][p]+Max_{l≤p≤q≤r}{{}dp[i-1][j-len][p][q][1][0]{}}\ dp[i][j][l][r][1][1]=sum_{p=l}^{r}a[i][p]+Max_{l≤p≤r≤q}{{}Max_{0≤y≤1}{{}dp[i-1][j-len][p][q][1][y]{}}{}}\ dp[i][j][l][r][0][0]=sum_{p=l}^{r}a[i][p]+Max_{p≤l≤q≤r}{{}Max_{0≤x≤1}{{}dp[i-1][j-len][p][q][x][0]{}}{}}\ dp[i][j][l][r][0][1]=sum_{p=l}^{r}a[i][p]+Max_{p≤l≤r≤q}{{}Max_{0≤x≤1}{{}Max_{0≤y≤1}{{}dp[i-1][j-len][p][q][x][y]{}}{}}{}} ]

    初始化都为0,目标状态:Max{dp(i,K,l,r,x,y)}。

    时间复杂度为O(N * M^4 * K)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 16
    #define maxm 226
    using namespace std;
     
    int dp[maxn][maxm][maxn][maxn][2][2];
    int n,m,sum,val[maxn][maxn];
    int ans;
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
     
    int main(){
        n=read(),m=read(),sum=read();
        for(register int i=1;i<=n;i++){
            for(register int j=1;j<=m;j++) val[i][j]=val[i][j-1]+read();
        }
     
        for(register int i=1;i<=n;i++){
            for(register int j=1;j<=sum;j++){
                for(register int l=1;l<=m;l++){
                    for(register int r=l;r<=m;r++){
                        if(j<r-l+1) break;
                        for(register int p=l;p<=r;p++){
                            for(register int q=p;q<=r;q++){
                                dp[i][j][l][r][1][0]=max(dp[i][j][l][r][1][0],dp[i-1][j-(r-l+1)][p][q][1][0]+val[i][r]-val[i][l-1]);
                            }
                        }
                        for(register int p=l;p<=r;p++){
                            for(register int q=r;q<=m;q++){
                                dp[i][j][l][r][1][1]=max(dp[i][j][l][r][1][1],max(dp[i-1][j-(r-l+1)][p][q][1][0],dp[i-1][j-(r-l+1)][p][q][1][1])+val[i][r]-val[i][l-1]);
                            }
                        }
                        for(register int p=1;p<=l;p++){
                            for(register int q=l;q<=r;q++){
                                dp[i][j][l][r][0][0]=max(dp[i][j][l][r][0][0],max(dp[i-1][j-(r-l+1)][p][q][0][0],dp[i-1][j-(r-l+1)][p][q][1][0])+val[i][r]-val[i][l-1]);
                            }
                        }
                        for(register int p=1;p<=l;p++){
                            for(register int q=r;q<=m;q++){
                                dp[i][j][l][r][0][1]=max(dp[i][j][l][r][0][1],max(dp[i-1][j-(r-l+1)][p][q][0][1],max(dp[i-1][j-(r-l+1)][p][q][1][0],max(dp[i-1][j-(r-l+1)][p][q][1][1],dp[i-1][j-(r-l+1)][p][q][0][0])))+val[i][r]-val[i][l-1]);
                            }
                        }
                        if(j==sum) ans=max(ans,max(dp[i][j][l][r][0][0],max(dp[i][j][l][r][1][0],max(dp[i][j][l][r][0][1],dp[i][j][l][r][1][1]))));
                    }
                }
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    判断输入的年份是闰年还是平年!!!
    键盘接收数,接收运算符号进行运算!!
    eclipse项目上如何传到码云上!新手,简单易懂,希望对你有所帮助。
    jquery dialog弹出框简单写法和一些属性的应用,写的不好,大佬勿喷!谢谢!
    新手冒泡排序,随机生成十个数。
    新手java九九乘法表
    Lambda表达式
    如何删除gitee仓库的文件
    Collection方法
    java冒泡排序的几种写法
  • 原文地址:https://www.cnblogs.com/akura/p/11045518.html
Copyright © 2011-2022 走看看