zoukankan      html  css  js  c++  java
  • SGU167 I-country

    嗯以前在某个DP专题了发过这道题,但是当时没码代码,现在重发一篇题解

    思考阶段如何划分:
    由已经处理的行数向下扩展,但是仅有行数我们无法描述状态空间
    那我们再加入已经选过的格子数,这样我们似乎可以确定我们已经完成了多少行,哪些格子已经选过
    但是这是凸连通块,我们靠以上两个信息还远远不够
    那么我们想一想如何使阶段转移完成后最终得到的是凸连通块,再加入什么信息?
    我们可以再加入每行的左端点和右端点,确定下一行端点的范围,以满足单调性
    那么我们还可以再加入轮廓的单调类型
    加起来5维
    f[i,j,l,r,x,y]
    表示前i行,选了j个格子,其中第i行选了第l到r的格子,左轮廓的单调性是x,右轮廓的单调性是r时,能构成的凸连通块的最大权值和
    行数和格子数可以作为dp的“阶段”,每次转移到下一行,同时选出的格子递增,符合“阶段线性增长”的特点

    然后我们会发现,我们在进行状态转移的时候,需要第i行中l到r的区间和,显然边转移边计算需要不低的复杂度,于是我们可以预处理出表示每一行的前缀和数组A,这样在计算时,l到r的区间和就可以表示为A[i][r]-A[i][l],在转移结束时,再定义两个变量p,q,表示当前行的左端点l和右端点r
    然后我们来写一下状态转移方程试试:
    根据我们的分析,我们可以得到4种可能状态://1表示递减,0表示递增
    1.左边界列号递减,右边界列号递增(两边界都处于扩张状态)
    f[i,j,l,r,1,0] = A[i][r]-A[i][l] + max{f[i-1,j-(r-l+1),p,q,1,0]};//j>r-l+1>0
    `     = A[i][r]-A[i][l] + max{f[i-1,0,0,0,1,0]};//j=r-l+1>0
    2.左右边界列号都递减(左边界扩张,右边界收缩)
    f[i,j,l,r,1,1] = A[i][r]-A[i][l] + max{max{f[i-1,j-(r-l+1),p,q,1,y]}(0<=y<=1)}
    3.左右边界列号都递减(左边界收缩,右边界扩张)
    f[i,j,l,r,0,0] = A[i][r]-A[i][l] + max{{f[i-1,j-(r-l+1),p,q,x,0](0<=x<=1)}}
    4.左边界列号递增,右边界列号递减(两边界都处于收缩状态)
    f[i,j,l,r,0,1] = A[i][r]-A[i][l] + max{max{max{f[i-1,j-(r-l+1),p,q,x,y]}(0<=y<=1)}(0<=x<=1)}(p<=l<=r<=q)
    对于2,3,4的max嵌套max,可能有点难以理解
    我们来想一下,我们要进行收缩,那么我们这个收缩的状态是怎么得来的?
    答:由上一行扩张或收缩而来
    所以当收缩右边界时,我们先比较的是上一行右边界标记扩张和右边界标记收缩的最大值,再和当前行比较
    左边界收缩时同理。
    这样我们就能推出2和3。
    进而我们想4这种情况。
    左右边界同时进行收缩,我们就要嵌套3次,先由上述确定右边界状态,再由已确定右边界状态来确定左边界状态,最后由已确定的左边界状态和右边界状态来确定当前行
    //此处状态单指标记为收缩或扩张,即上一行的左/右边界由上上一行的左/右边界扩张或收缩得到

    本题还要求输出方案。
    在动态规划需要给出方案时,通常做法是额外使用一些与DP状态大小相同的数组记录下来每个状态,通过递归返回最初的状态,然后逐层退出的同时输出方案

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 int f[20][230][20][20][2][2];
      4 int lcw[20][230][20][20][2][2];//What did you choose on the left 
      5 int rcw[20][230][20][20][2][2];//What did you choose on the right 
      6 int lud[20][230][20][20][2][2];//The left is up or down
      7 int rud[20][230][20][20][2][2];//The right is up or down
      8 int n, m, k;
      9 
     10 int ans = 0, ie, le, re, xe, ye;
     11 
     12 int i, j, l, r, il, ir, x, y;
     13 
     14 int a[20][20], b[20][20];
     15 
     16 inline int read() {
     17     int x = 0, y = 1;
     18     char ch = getchar();
     19     while(!isdigit(ch)) {
     20         if(ch == '-') y = -1;
     21         ch = getchar();
     22     }
     23     while(isdigit(ch)) {
     24         x = (x << 1) + (x << 3) + ch - '0';
     25         ch = getchar();
     26     }
     27     return x * y;
     28 }
     29 
     30 inline void update(int val, int L, int R, int X, int Y) {
     31     if(val < f[i][j][l][r][x][y]) return;
     32     f[i][j][l][r][x][y] = val;
     33     lcw[i][j][l][r][x][y] = L, rcw[i][j][l][r][x][y] = R;
     34     lud[i][j][l][r][x][y] = X, rud[i][j][l][r][x][y] = Y;
     35 }
     36 
     37 void print(int i, int j, int l, int r, int x, int y) {
     38     if(!j) return;
     39     print(i - 1, j - (r - l + 1), lcw[i][j][l][r][x][y], rcw[i][j][l][r][x][y], lud[i][j][l][r][x][y], rud[i][j][l][r][x][y]);
     40     for(j = l; j <= r; ++j) printf("%d %d
    ", i, j);
     41 } 
     42 
     43 int main() {
     44     freopen("input.in", "r", stdin);
     45     freopen("output.out", "w", stdout);
     46     memset(f, 0xcf, sizeof(f));
     47     n = read(), m = read(), k = read();
     48     for(i = 1; i <= n; ++i)
     49         for(int j = 1; j <= m; ++j) {
     50             a[i][j] = read();
     51             b[i][j] = b[i][j - 1] + a[i][j];
     52         }
     53     for(i = 1; i <= n; ++i)
     54         for(j = 1; j <= k; ++j) 
     55             for(l = 1; l <= m; ++l)
     56                 for(r = l; r <= m; ++r) {//后两个维度,0表示递增,1表示递减 
     57                     int len = r - l + 1, pow;
     58                     if(len > j) break;
     59                     pow = b[i][r] - b[i][l - 1];
     60                     for(x = 0; x < 2; ++x)
     61                         for(y = 0; y < 2; ++y) 
     62                             update(pow, m, 0, x, y);
     63                     x = y = 1;
     64                     for(int p = l; p <= r; ++p)
     65                         for(int q = p; q <= r; ++q)
     66                             update(f[i - 1][j - len][p][q][1][1] + pow, p, q, 1, 1);
     67                     x = y = 0;
     68                     for(int p = 1; p <= l; ++p)
     69                         for(int q = r; q <= m; ++q) {
     70                             update(f[i - 1][j - len][p][q][0][0] + pow, p, q, 0, 0);
     71                             update(f[i - 1][j - len][p][q][0][1] + pow, p, q, 0, 1);
     72                             update(f[i - 1][j - len][p][q][1][0] + pow, p, q, 1, 0);
     73                             update(f[i - 1][j - len][p][q][1][1] + pow, p, q, 1, 1);
     74                         } 
     75                     x = 1, y = 0;
     76                     for(int p = l; p <= r; ++p)
     77                         for(int q = r; q <= m; ++q) {
     78                             update(f[i - 1][j - len][p][q][1][0] + pow, p, q, 1, 0);
     79                             update(f[i - 1][j - len][p][q][1][1] + pow, p, q, 1, 1);
     80                         }
     81                     x = 0, y = 1;
     82                     for(int p = 1; p <= l; ++p)
     83                         for(int q = l; q <= r; ++q) {
     84                             update(f[i - 1][j - len][p][q][0][1] + pow, p, q, 0, 1);
     85                             update(f[i - 1][j - len][p][q][1][1] + pow, p, q, 1, 1);
     86                         }
     87                 } 
     88     for(i = 1; i <= n; ++i)
     89         for(l = 1; l <= m; ++l)
     90             for(r = l; r <= m; ++r)
     91                 for(x = 0; x < 2; ++x)
     92                     for(y = 0; y < 2; ++y) {
     93                         if(ans < f[i][k][l][r][x][y]) {
     94                             ans = f[i][k][l][r][x][y];
     95                             ie = i, le = l, re = r, 
     96                             xe = x, ye = y;
     97                         }
     98                     }
     99     printf("Oil : %d
    ", ans);
    100     print(ie, k, le, re, xe, ye);
    101     return 0;
    102 }
  • 相关阅读:
    CodingTrip
    CodingTrip
    Linux下面查找含有特定的字符的文件
    Linux下TCP/IP协议的Socket编程
    显示Apache服务器里面访问量排在前10的ip地址
    c语言的详细编译过程
    WebStorm设置编辑器中的字体大小
    Sublime多行编辑快捷键
    Aptana 中去掉“Missing semicolon”提醒
    公认的媒体类型
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9744362.html
Copyright © 2011-2022 走看看