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

本文探讨了如何使用动态规划算法解决一个关于N×M矩阵中找到包含K个格子的凸连通块问题,目标是最大化连通块内的权值和,并提供了详细的步骤和代码实现。关键在于定义状态转移方程并划分四种边界情况来递推求解。

动态规划(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);
}
在这个脚本基础上优化 @echo off setlocal enabledelayedexpansion :: ---------------------------- :: 基础配置(可修改区域) :: ---------------------------- set "UV=F:\Software\keil5\core\UV4\UV4.exe" set "project_root=%~dp0Multi_project" :: 工程根目录 :: ---------------------------- :: 命令行参数处理 :: ---------------------------- if not "%~1"=="" ( set "TARGET_PROJECT=%~1" call :validate_project call :compile exit /b %errorlevel% ) :: ---------------------------- :: 自动检测所有子工程 :: ---------------------------- echo Scanning projects in: %project_root% set "project_count=0" for /d %%a in ("%project_root%\*") do ( set /a "project_count+=1" set "project_name=%%~nxa" set "project_list=!project_list! !project_name!" ) echo Found %project_count% project(s) :: ---------------------------- :: 主编译流程 :: ---------------------------- for %%a in (%project_list%) do ( set "TARGET_PROJECT=%%a" call :compile if errorlevel 1 ( echo [ERROR] Build failed for: %%a exit /b 1 ) ) exit /b 0 :: ---------------------------- :: 子程序:工程验证 :: ---------------------------- :validate_project if not exist "%project_root%\%TARGET_PROJECT%" ( echo [ERROR] Project not exist: %TARGET_PROJECT% exit /b 2 ) if not exist "%project_root%\%TARGET_PROJECT%\%TARGET_PROJECT%_MCU.uvmpw" ( echo [ERROR] Project file missing: %TARGET_PROJECT%_MCU.uvmpw exit /b 3 ) exit /b 0 :: ---------------------------- :: 子程序:编译流程 :: ---------------------------- :compile echo. echo [INFO] Building project: %TARGET_PROJECT% :: 路径配置(自动生成带时间戳的日志文件) set "build_log=%~dp0logs\%TARGET_PROJECT%_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%.log" set "uvproj_path=%project_root%\%TARGET_PROJECT%\%TARGET_PROJECT%_MCU.uvmpw" :: 清理并创建日志目录 if not exist "%~dp0logs\" md "%~dp0logs" break > "%build_log%" :: 执行编译命令 echo Project file: %uvproj_path% "%UV%" -j0 -r "%uvproj_path%" -o "%build_log%" :: ---------------------------- :: 错误检查 :: ---------------------------- if not exist "%build_log%" ( echo [ERROR] Log file missing: %build_log% exit /b 4 ) type "%build_log%" | findstr /i /r "\<Error\>" "\<error(s)\>" "\<错误\>" if %errorlevel% equ 0 ( echo [ERROR] Compilation failed: %TARGET_PROJECT% exit /b 1 ) echo [SUCCESS] Build completed: %TARGET_PROJECT% exit /b 0
03-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值