动态规划(DP):I-区域

动态规划(DP):I-区域

题目:

在 N×M 的矩阵中,每个格子有一个权值,要求寻找一个包含 K
个格子的凸连通块(连通块中间没有空缺,并且轮廓是凸的),使这个连通块中的格子的权值和最大。

注意:凸连通块是指:连续的若干行,每行的左端点列号先递减、后递增,右端点列号先递增、后递减。

求出这个最大的权值和,并给出连通块的具体方案,输出任意一种方案即可。

输入格式 第一行包含三个整数 N,M 和 K。

接下来 N 行每行 M 个整数,表示 N×M 的矩阵上每个格子的权值(均不超过 1000)。

输出格式 第一行输出 Oil : X,其中 X 为最大权值和。

接下来 K 行每行两个整数 xi 和 yi,用来描述所有格子的具体位置,每个格子位于第 xi 行,第 yi 列。

数据范围 1≤N,M≤15, 0≤K≤N×M

思路:
一个凸连通块可以按行分为若干段连续区间[L,R],并且从上到下这些区间具有凸的性质(先向外扩张,再向内收缩,可以不完整),所以将DP的阶段设为每一行,一共n个阶段;然后考虑每个阶段内状态如何转移,对于一行中,需要关注的状态有当前选取的区间[L,R],当前区间收缩或扩张的趋势(依据这一点,每个阶段中分为四种情况,对于每一边都有如下的状态机)。
自己画的
用F[i,j,l,r,x,y] (i表示当前行数,j表示当前已经划入凸连通块的块数,l表示当前行的左端点,r表示当前行的右端点,x表示左边界单调性类型,y表示右边界单调性类型)表示当前的状态。
我们可以得到状态转移方程:
蓝书上的
至于选择的点:可以标记每步状态时如何转移过来的,递归求解或用栈求解

#include<bits/stdc++.h>
using namespace std;
const int N=17;
int a[N][N],sum[N][N];
int dp[N][N*N][N][N][2][2];
struct node{
	int i,j,l,r,x,y;
}fa[N][N*N][N][N][2][2];
struct node mm;

void print(int i,int j,int l,int r,int x,int y)
{
	if(j==0) return ;
	//printf("%d %d %d %d %d %d\n",i,j,l,r,x,y);
	struct node &now=fa[i][j][l][r][x][y];
	
	print(now.i,now.j,now.l,now.r,now.x,now.y);
	
	for(int k=l;k<=r;k++) printf("%d %d\n",i,k);
	return ;
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&	m,&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            sum[i][j]=sum[i][j-1]+a[i][j];
        }
    }
    int ans=0;
    for(int i = 0; i <= n; i++)
	{
        for(int l = 1; l <= m; l++)
		{
            for(int r = l; r <= m; r++)
            {
                dp[i][0][l][r][0][0] = 0;           	
			}

        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int l=1;l<=m;l++)
        {
            for(int r=l;r<=m;r++)
            {
                int s=sum[i][r]-sum[i][l-1];
                for(int j=r-l+1;j<=k;j++)
                {
                    //计算相关值
                    int ma00=0,ma01=0,ma10=0,ma11=0;
					struct node fa00,fa01,fa10,fa11;
                    for(int p=l;p<=r;p++)
                    {
                        for(int q=p;q<=r;q++)
                        {
                            if(ma10<dp[i-1][j-(r-l+1)][p][q][1][0])
                            {
                            	ma10=dp[i-1][j-(r-l+1)][p][q][1][0];
                            	fa10={i-1,j-(r-l+1),p,q,1,0};
							}
                        }
                    }
                    for(int p=l;p<=r;p++)
                    {
                        for(int q=r;q<=m;q++)
                        {
                            if(ma11<dp[i-1][j-(r-l+1)][p][q][1][1])
                            {
                            	ma11=dp[i-1][j-(r-l+1)][p][q][1][1];
                            	fa11={i-1,j-(r-l+1),p,q,1,1};
							}
							if(ma11<dp[i-1][j-(r-l+1)][p][q][1][0])
							{
								ma11=dp[i-1][j-(r-l+1)][p][q][1][0];
                            	fa11={i-1,j-(r-l+1),p,q,1,0};
							}
                        }
                    }
                    for(int p=1;p<=l;p++)
                    {
                        for(int q=l;q<=r;q++)
                        {
                            if(ma00<dp[i-1][j-(r-l+1)][p][q][1][0])
                            {
                            	ma00=dp[i-1][j-(r-l+1)][p][q][1][0];
                            	fa00={i-1,j-(r-l+1),p,q,1,0};
							}
							if(ma00<dp[i-1][j-(r-l+1)][p][q][0][0])
							{
								ma00=dp[i-1][j-(r-l+1)][p][q][0][0];
								fa00={i-1,j-(r-l+1),p,q,0,0};
							}
                        }
                    }
                    for(int p=1;p<=l;p++)
                    {
                        for(int q=r;q<=m;q++)
                        {
                        	if(ma01<dp[i-1][j-(r-l+1)][p][q][1][0])
                            {
                            	ma01=dp[i-1][j-(r-l+1)][p][q][1][0];
                            	fa01={i-1,j-(r-l+1),p,q,1,0};
							}
							if(ma01<dp[i-1][j-(r-l+1)][p][q][0][0])
							{
								ma01=dp[i-1][j-(r-l+1)][p][q][0][0];
								fa01={i-1,j-(r-l+1),p,q,0,0};
							}
							if(ma01<dp[i-1][j-(r-l+1)][p][q][1][1])
                            {
                            	ma01=dp[i-1][j-(r-l+1)][p][q][1][1];
                            	fa01={i-1,j-(r-l+1),p,q,1,1};
							}
							if(ma01<dp[i-1][j-(r-l+1)][p][q][0][1])
                            {
                            	ma01=dp[i-1][j-(r-l+1)][p][q][0][1];
                            	fa01={i-1,j-(r-l+1),p,q,0,1};
							}
                        }
                    }
                    
                    //转移
                    if(j==r-l+1)
                    {
                    	dp[i][j][l][r][1][0]=s+dp[i-1][0][0][0][1][0];
                    	fa[i][j][l][r][1][0]={i-1,0,0,0,1,0};
					}
                    else
                    {
                    	dp[i][j][l][r][1][0]=s+ma10;
                    	fa[i][j][l][r][1][0]=fa10;
					}
                    dp[i][j][l][r][1][1]=s+ma11;
                    fa[i][j][l][r][1][1]=fa11;
                    dp[i][j][l][r][0][0]=s+ma00;
                    fa[i][j][l][r][0][0]=fa00;
                    dp[i][j][l][r][0][1]=s+ma01;
                    fa[i][j][l][r][0][1]=fa01;
                    
                    //更新答案
                    if(ans<=dp[i][j][l][r][1][0]) ans=dp[i][j][l][r][1][0],mm={i,j,l,r,1,0};
                    if(ans<=dp[i][j][l][r][1][1]) ans=dp[i][j][l][r][1][1],mm={i,j,l,r,1,1};
                    if(ans<=dp[i][j][l][r][0][0]) ans=dp[i][j][l][r][0][0],mm={i,j,l,r,0,0};
                    if(ans<=dp[i][j][l][r][0][1]) ans=dp[i][j][l][r][0][1],mm={i,j,l,r,0,1};
                }
            }
        }
    }
    printf("Oil : %d\n",ans);
    print(mm.i,mm.j,mm.l,mm.r,mm.x,mm.y);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值