分享

CH5104题解

 印度阿三17 2020-11-24

CH5104:I-Country题解(线性DP)

MDZZ这道题调了2个小时自闭了((

题意简述

给你一个\(N*M\)的矩阵,每个格子都有一个权值。现在让你寻找一个包含\(K\)个格子的凸连通块,使得这个连通块的权值之和最大,求出这个最大的权值和,并给出连通块的具体方案

题意分析

这道题主要难理解的东西就是凸连通块

凸连通块是什么意思呢?就是整个图形的外轮廓不能突然凹下去一块,中间也不能有空缺。理性的说,任意两点连成的线段,如果经过图形,那么只能经过一个部分,不可能进去\(\to\)出来\(\to\)又进去。

总结:我们把这个连通块分成若干行,每行的左端点列号先递减,后递增;右端点列号先递增,后递减;满足单调性。

题目分析

这道题真的很F**K

首先,我们可以看出这是一道\(DP\)的题。

我们需要关注那些信息呢?

\((1)\).当前已经处理过了多少行;

\((2)\).已经选拔出了多少个格子;

\((3)\).当前行已选的格子的左端点——用于确定下一行左端点的可行范围;

\((4)\).当前行已选的格子的右端点——用于确定下一行右端点的可行范围;

\((5).\)当前左侧轮廓的单调性类型;

\((6).\)当前右侧轮廓的单调性类型;

好吧我得实话告诉你这些东西都要记录在\(dp\)数组中(啊这~)。

由此我们定义状态:\(dp_{i,j,l,r,x,y}\)

这个状态表示:前\(i\)行总共已经选了\(j\)个格子,其中第\(i\)行选择了第\(l\)到\(r\)个格子(均为\(0\)表示都不选),左边界的单调性为\(x\),右边界的单调性为\(y\)时能构成的连通块的最大权值之和。 (\(0\)表示递增,\(1\)表示递减)

这道题的状态转移方程挺好理解的,如下:

\((1).\)左边界的列号递减,右边界的列号递增(此时两个边界都处于扩张状态)

\(if \space \space j=r-l 1>0:\) \(dp_{i,j,l,r,1,0}=\sum^{r}_{p=l}A_{i,p} dp_{i-1,0,0,0,1,0}\)

\(if \space \space j>r-l 1>0:\) \(dp_{i,j,l,r,1,0}=\sum^{r}_{p=l}A_{i,p} max_{l\le p\le q\le r} {dp_{i-1,j-(r-l 1),p,q,1,0}}\)

\((2).\)左右的列号都递减(左边界扩张,右边界收缩)

\(dp_{i,j,l,r,1,1}=\sum^r_{p=l} \max_{l\le p \le r \le q} {\max_{0\le y \le 1}} {dp_{i-1,j-(r-l 1),p,q,1,y}}\)

\((3).\)左右的列号都递增(左边界收缩,右边界扩张)

\(dp_{i,j,l,r,0,0}=\sum^r_{p=l} \max_{p\le l \le q \le r} {\max_{0\le x \le 1}} {dp_{i-1,j-(r-l 1),p,q,x,0}}\)

\((4).\)左边界的列号递增,右边界的列号递减(此时两个边界都处于收缩状态)

\(dp_{i,j,l,r,0,1}={\sum^r_{p=l}A_{i,p} \max_{p\le l \le r \le q}{\max_{0\le x \le 1}}{\max_{0\le y\le 1}dp_{i-1,j-(r-l 1),p,q,x,y}}}\)

很明显初始状态\(dp_{i,0,0,0,1,0}=0\),目标状态是\(\max dp_{i,K,l,r,x,y}\),时间复杂度\(\Theta (NM^4K)=\Theta (N^2M^5)\)

#include<bits/stdc  .h>
using namespace std;
const int N=20;
struct path
{
int i,k,l,fl,r,fr;
}pre[N][N*N][N][2][N][2],anss;
int n,m,K,ans;
int mp[N][N],sum[N][N];
int dp[N][N*N][N][2][N][2];
void print(path x)
{
if(x.l==x.r && x.l==0) return;
for(int i=x.l;i<=x.r;i  ) printf("%d %d\n",x.i,i);
print(pre[x.i][x.k][x.l][x.fl][x.r][x.fr]);
}
int read()
{
    int x=0,f=1;
    char c=getchar();
    while (c<'0'||c>'9')
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while (c>='0'&&c<='9')
    {
        x=(x<<1) (x<<3) (c^48);
        c=getchar();
    }
    return x*f;
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;i  ) for(int j=1;j<=m;j  ) mp[i][j]=read(),sum[i][j]=sum[i][j-1] mp[i][j];
for(int i=1;i<=n;i  )
    {
        for(int k=1;k<=K;k  )
        {
            for(int l=1;l<=m;l  )
            {
                for(int r=l;r<=m;r  )
{
int len=r-l 1,val=sum[i][r]-sum[i][l-1];
if(len>k) continue;
if(len==k)
{
dp[i][k][l][0][r][0]=val;
pre[i][k][l][0][r][0]=path{0,0,0,0,0,0};
if(dp[i][k][l][0][r][0]>ans)
{
ans=dp[i][k][l][0][r][0];
anss=path{i,k,l,0,r,0};
}
continue;
}
for(int l1=l;l1<=r;l1  )
                    {
                        for(int r1=l1;r1<=r;r1  )
{
int len1=r1-l1 1;
if(len1>k-len) continue;
if(dp[i-1][k-len][l1][0][r1][0] val>dp[i][k][l][0][r][0])
{
dp[i][k][l][0][r][0]=dp[i-1][k-len][l1][0][r1][0] val;
pre[i][k][l][0][r][0]=path{i-1,k-len,l1,0,r1,0};
}
if(dp[i][k][l][0][r][0]>ans)
{
ans=dp[i][k][l][0][r][0];
anss=path{i,k,l,0,r,0};
}
}
                    }//0 0
for(int l1=1;l1<=l;l1  )
                    {
                        for(int r1=l;r1<=r;r1  )
{
int len1=r1-l1 1;
if(len1>k-len) continue;
if(dp[i-1][k-len][l1][0][r1][0] val>dp[i][k][l][1][r][0])
{
dp[i][k][l][1][r][0]=dp[i-1][k-len][l1][0][r1][0] val;
pre[i][k][l][1][r][0]=path{i-1,k-len,l1,0,r1,0};
}
if(dp[i-1][k-len][l1][1][r1][0] val>dp[i][k][l][1][r][0])
{
dp[i][k][l][1][r][0]=dp[i-1][k-len][l1][1][r1][0] val;
pre[i][k][l][1][r][0]=path{i-1,k-len,l1,1,r1,0};
}
if(dp[i][k][l][1][r][0]>ans)
{
ans=dp[i][k][l][1][r][0];
anss=path{i,k,l,1,r,0};
}
}
                    }//1 0
for(int l1=l;l1<=r;l1  )
                    {
                        for(int r1=r;r1<=m;r1  )
{
int len1=r1-l1 1;
if(len1>k-len) continue;
if(dp[i-1][k-len][l1][0][r1][0] val>dp[i][k][l][0][r][1])
{
dp[i][k][l][0][r][1]=dp[i-1][k-len][l1][0][r1][0] val;
pre[i][k][l][0][r][1]=path{i-1,k-len,l1,0,r1,0};
}
if(dp[i-1][k-len][l1][0][r1][1] val>dp[i][k][l][0][r][1])
{
dp[i][k][l][0][r][1]=dp[i-1][k-len][l1][0][r1][1] val;
pre[i][k][l][0][r][1]=path{i-1,k-len,l1,0,r1,1};
}
if(dp[i][k][l][0][r][1]>ans)
{
ans=dp[i][k][l][0][r][1];
anss=path{i,k,l,0,r,1};
}
}
                    }//0 1

for(int l1=1;l1<=l;l1  )
                    {
                        for(int r1=r;r1<=m;r1  )
{
int len1=r1-l1 1;
if(len1>k-len) continue;
if(dp[i-1][k-len][l1][0][r1][0] val>dp[i][k][l][1][r][1])
{
dp[i][k][l][1][r][1]=dp[i-1][k-len][l1][0][r1][0] val;
pre[i][k][l][1][r][1]=path{i-1,k-len,l1,0,r1,0};
}
if(dp[i-1][k-len][l1][0][r1][1] val>dp[i][k][l][1][r][1])
{
dp[i][k][l][1][r][1]=dp[i-1][k-len][l1][0][r1][1] val;
pre[i][k][l][1][r][1]=path{i-1,k-len,l1,0,r1,1};
}
if(dp[i-1][k-len][l1][1][r1][0] val>dp[i][k][l][1][r][1])
{
dp[i][k][l][1][r][1]=dp[i-1][k-len][l1][1][r1][0] val;
pre[i][k][l][1][r][1]=path{i-1,k-len,l1,1,r1,0};
}
if(dp[i-1][k-len][l1][1][r1][1] val>dp[i][k][l][1][r][1])
{
dp[i][k][l][1][r][1]=dp[i-1][k-len][l1][1][r1][1] val;
pre[i][k][l][1][r][1]=path{i-1,k-len,l1,1,r1,1};
}
if(dp[i][k][l][1][r][1]>ans)
{
ans=dp[i][k][l][1][r][1];
anss=path{i,k,l,1,r,1};
}
}
                    }//1 1
}
            }
        }
    }
printf("Oil : %d\n",ans);
print(anss);
return 0;
}
来源:https://www./content-4-762451.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多