zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x51线性DP I-区域

    题目链接:https://www.acwing.com/problem/content/278/

    题目给出一个n*m的矩阵,要求从中找出一个凸连通块,使得该连通块包含k个格子并且格子数之和最大,凸连通块由若干行构成,左右最多各有一个峰值。

    可通过DP解决,每行处理完代表一个阶段,f[i,j,l,r,x,y]表示当前处理第i行,一共选择了j个格子,第i行选择的格子是[l,r],左右的状态是x,y表示下降或者上升。转移时要枚举每一种状态,并且枚举上一个阶段的左右位置。找到最大的一个,在加上第i行的静态的[l,r]的和。

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn = 16;
    int f[maxn][maxn*maxn][maxn][maxn][2][2];
    
    struct State{//保存行数,格子数,左端点右端点,上升和递减的状态 
        int i,j,l,r,x,y;
    }g[maxn][maxn*maxn][maxn][maxn][2][2];
    
    int n,m,k;
    int w[maxn][maxn];
    int main(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>w[i][j];
                
        for(int i=1;i<=n;i++)
            for(int j=0;j<=k;j++)
                for(int l=1;l<=m;l++)
                    for(int r=l;r<=m;r++)
                    {
                        if(j<(r-l+1))continue;
                        //左边扩张,右边扩张 
                        {
                            int& vf=f[i][j][l][r][1][0];
                            State& vg=g[i][j][l][r][1][0];
                            //找到从上一个状态扩展来的最大的一个状态 
                            for(int p=l;p<=r;p++)
                                for(int q=p;q<=r;q++)
                                {
                                    int val=f[i-1][j-(r-l+1)][p][q][1][0];
                                    if(vf<val){
                                        vf=val;
                                        vg={i-1,j-(r-l+1),p,q,1,0};//记录上一个状态 
                                    }
                                }
                            for(int u=l;u<=r;u++)vf+=w[i][u]; 
                        }
                        //左边收缩,右边扩张 
                        {
                            int &vf=f[i][j][l][r][0][0];
                            State &vg=g[i][j][l][r][0][0];
                            //找到从上一个状态扩展来的最大的一个状态 
                            for(int p=1;p<=l;p++)
                                for(int q=l;q<=r;q++)
                                    for(int x=0;x<=1;x++) 
                                    {
                                        int val=f[i-1][j-(r-l+1)][p][q][x][0];
                                        if(vf<val){
                                            vf=val;
                                            vg={i-1,j-(r-l+1),p,q,x,0};//记录上一个状态 
                                        }
                                    }
                            for(int u=l;u<=r;u++)vf+=w[i][u]; 
                        }
                        //左边收缩,右边收缩 
                        {
                            int &vf=f[i][j][l][r][0][1];
                            State &vg=g[i][j][l][r][0][1];
                            //找到从上一个状态扩展来的最大的一个状态 
                            for(int p=1;p<=l;p++)
                                for(int q=r;q<=m;q++)
                                    for(int x=0;x<=1;x++)
                                        for(int y=0;y<=1;y++) 
                                        {
                                            int val=f[i-1][j-(r-l+1)][p][q][x][y];
                                            if(vf<val){
                                                vf=val;
                                                vg={i-1,j-(r-l+1),p,q,x,y};//记录上一个状态 
                                            }
                                        }
                            for(int u=l;u<=r;u++)vf+=w[i][u]; 
                        }
                        //左边扩张,右边收缩 
                        {
                            int &vf=f[i][j][l][r][1][1];
                            State &vg=g[i][j][l][r][1][1];
                            //找到从上一个状态扩展来的最大的一个状态 
                            for(int p=l;p<=r;p++)
                                for(int q=r;q<=m;q++)
                                    for(int y=0;y<=1;y++) 
                                    {
                                        int val=f[i-1][j-(r-l+1)][p][q][1][y];
                                        if(vf<val){
                                            vf=val;
                                            vg={i-1,j-(r-l+1),p,q,1,y};//记录上一个状态 
                                        }
                                    }
                            for(int u=l;u<=r;u++)vf+=w[i][u]; 
                        }
                    }
        
        int res=0;
        State state;
        //查找最大的终态 
        for(int i=1;i<=n;i++)
            for(int l=1;l<=m;l++)
                for(int r=1;r<=m;r++)
                    for(int x=0;x<=1;x++)
                        for(int y=0;y<=1;y++)
                            if(f[i][k][l][r][x][y]>res){
                                res=f[i][k][l][r][x][y];
                                state={i,k,l,r,x,y};
                            }
        printf("Oil : %d
    ",res);
        while(state.j){//该状态中还有没算到的格子 
            for(int i=state.l;i<=state.r;i++)
                printf("%d %d
    ",state.i,i);
            state=g[state.i][state.j][state.l][state.r][state.x][state.y];
        }                            
        return 0;
    }
  • 相关阅读:
    oracle中xhost报错
    cronolog切割apache和tomcat日志
    rsync配置和同步数据
    Jenkins+GitHub+maven
    Git只获取部分目录的内容
    git命令综合
    tomcat(不仅仅是tomcat)通过熵池解决在linux启动应用慢
    iptables之ipset集群工具
    Python中yield表达式的使用
    对于python中出现UnicodeDecodeError问题的解决方案
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13389557.html
Copyright © 2011-2022 走看看