AcWing276. I-区域 (线性DP)

在 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

输入样例:

2 3 4
10 20 30
40 2 3

输出样例:

Oil : 100
1 1
1 2
1 3
2 1

题解:

思路:逐行求解,跟随当前已经处理的数目, 还有当前行数的左右列坐标,还有趋势
(因为必须是凸的图形)

需要储存的状态:

  1. i 当前处理完的行数
  2. j 已经选出的格子数
  3. l 当前行已选格子的左端位置
  4. j 当前行已选格子的右端位置
  5. x 当前左侧轮廓单调类型
  6. y 当前右侧轮廓单调类型

记作f[i][j][l][r][x][y]

性质:
左右两条边单调性只会变化一次,即由扩张变为收缩

我们由第一行开始DP,如果有j<r-l+1不合法的话,直接略过。
每次都要计算当前i,j,l,r的 左右扩张,左扩张与右收缩,左收缩与右扩张,左右收缩 四个状态。

我们用1来表示想左,0来表示向右

左右扩张:
在这里插入图片描述
左右扩张情况下,上面i-1行也必然是左右扩张,只需枚举出值最大的段再加上当前l->r的值就好了,即for (int p = l; p <= r; p++) for (int q = p; q <= r; q++) val=max(val,f[i - 1][j - (r - l + 1)][p][q][1][0])
需要注意的是当j==r-l+1时,即当前行才是图形的第一行时,不需要计算上一行了

左扩张与右收缩:
在这里插入图片描述这种情况下单调性已经变化过的边,i-1行会有两种可能性,即变化与未变化 要都枚举到

剩下的就不过多赘述了

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 16
int n,m,k;
int f[N][N*N][N][N][2][2];
int a[N][N];

struct node{
    int i,j,l,r,x,y;
}g[N][N*N][N][N][2][2];

int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];

    memset(f,-1,sizeof f);
    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;
                    {
                        auto &vf=f[i][j][l][r][1][0];
                        auto &vg=g[i][j][l][r][1][0];
                        if(j==r-l+1) vf=0;
                        else {
                            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+=a[i][u];
                    }

                    {
                        auto &vf=f[i][j][l][r][1][1];
                        auto &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+=a[i][u];
                    }

                    {
                        auto &vf=f[i][j][l][r][0][0];
                        auto &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+=a[i][u];
                    }

                    {
                        auto &vf=f[i][j][l][r][0][1];
                        auto &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+=a[i][u];
                    }
                }

    int ans=0;
    node t;
    for(int i=1;i<=n;i++)
            for(int l=1;l<=m;l++)
                for(int r=l;r<=m;r++)
                    for (int x = 0; x <= 1; x ++ )
                        for (int y = 0; y <= 1; y ++ ){
                            if(ans<f[i][k][l][r][x][y]){
                                ans=f[i][k][l][r][x][y];
                                t={i,k,l,r,x,y};
                            }
                        }

    cout<<"Oil : "<<ans<<endl;
    while(t.j){
        for(int i=t.l;i<=t.r;i++) cout<<t.i<<' '<<i<<endl;
        t=g[t.i][t.j][t.l][t.r][t.x][t.y];
    }
    return 0;
}
发布了38 篇原创文章 · 获赞 5 · 访问量 842

猜你喜欢

转载自blog.csdn.net/Fooooooo/article/details/104301700