【插头DP】 HYSBZ 1187 神奇游乐园

通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1187

题意:单回路,权值,可选可不选,权值和最大。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4
  5 using namespace std;
  6
  7 const int MAX_N = 107;
  8 const int MAX_M = 7;
  9 const int HASH = 1007;
 10 const int MAX_S = 1000007;
 11
 12 struct node {
 13     int head[HASH], nxt[MAX_S], dp[MAX_S], st[MAX_S];
 14     int cnt;
 15     void cr() {
 16         memset(head, -1, sizeof head);
 17         cnt = 0;
 18     }
 19     void push(int s, int v) {
 20         int now = s % HASH;
 21         for(int i = head[now]; ~i; i = nxt[i]) {
 22             int p = st[i];
 23             if(p == s) {
 24                 dp[i] = max(dp[i], v);
 25                 return;
 26             }
 27         }
 28         st[cnt] = s;
 29         dp[cnt] = v;
 30         nxt[cnt] = head[now];
 31         head[now] = cnt++;
 32         return;
 33     }
 34 }d[2];
 35
 36 int n, m;
 37 int ans = -1e9;
 38 int a[MAX_N][MAX_M];
 39
 40 int find_pos(int s, int p) {
 41     return (s >> (p << 1)) & 3;
 42 }
 43
 44 void tp(int &s, int p, int v) {
 45     s &= (~(3 << (p << 1)));
 46     s |= (v << (p << 1));
 47 }
 48
 49 int find_r(int s, int p) {
 50     int cnt = 0;
 51     for(int i = p; i <= m; ++i) {
 52         if(find_pos(s, i) == 1) ++cnt;
 53         else if(find_pos(s, i) == 2) --cnt;
 54         if(!cnt) return i;
 55     }
 56 }
 57
 58 int find_l(int s, int p) {
 59     int cnt = 0;
 60     for(int i = p; i >= 0; --i) {
 61         if(find_pos(s, i) == 2) ++cnt;
 62         else if(find_pos(s, i) == 1) --cnt;
 63         if(!cnt) return i;
 64     }
 65 }
 66
 67 void dpblock(int i, int j, int cur) {
 68     for(int k = 0; k < d[cur].cnt; ++k) {
 69         int t = d[cur].st[k];
 70         int l = find_pos(t, j - 1), r = find_pos(t, j);
 71         if(l && r) {
 72             if(l == 1 && r == 1) {
 73                 int tpos = find_r(t, j);
 74                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1);
 75                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 76             } else if(l == 2 && r == 1) {
 77                 tp(t, j - 1, 0); tp(t, j, 0);
 78                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 79             } else if(l == 2 && r == 2) {
 80                 int tpos = find_l(t, j - 1);
 81                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2);
 82                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 83             } else { // 最后一个非障碍格子
 84                 tp(t, j - 1, 0); tp(t, j, 0);
 85                 if(!t) ans = max(ans, d[cur].dp[k] + a[i][j]);
 86             }
 87         } else if(l) {
 88             if(i < n) {
 89                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 90             }
 91             if(j < m) {
 92                 tp(t, j - 1, 0); tp(t, j, l);
 93                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 94             }
 95         } else if(r) {
 96             if(j < m) {
 97                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
 98             }
 99             if(i < n) {
100                 tp(t, j - 1, r); tp(t, j, 0);
101                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]);
102             }
103         } else { // 新建
104             d[cur ^ 1].push(t, d[cur].dp[k]); //不选
105             if(i < n && j < m) {
106                 tp(t, j - 1, 1); tp(t, j, 2);
107                 d[cur ^ 1].push(t, d[cur].dp[k] + a[i][j]); //选
108             }
109         }
110     }
111 }
112
113 int main() {
114     scanf("%d%d", &n, &m);
115     for(int i = 1; i <= n; i ++) {
116         for(int j = 1; j <= m; j ++) {
117             scanf("%d", &a[i][j]);
118         }
119     }
120     int cur = 0;
121     d[cur].cr();
122     d[cur].push(0, 0);
123     for(int i = 1; i <= n; i ++) {
124         for(int j = 1; j <= m; j ++) {
125             d[cur ^ 1].cr();
126             dpblock(i, j, cur);
127             cur ^= 1;
128         }
129         for(int k = 0; k < d[cur].cnt; k ++) {
130             d[cur].st[k] <<= 2;
131         }
132     }
133     printf("%d\n", ans);
134     return 0;
135 }

时间: 2024-08-01 17:54:46

【插头DP】 HYSBZ 1187 神奇游乐园的相关文章

【插头DP】BZOJ1187- [HNOI2007]神奇游乐园

[题目大意] 在n*m的网格中选一条回路,使权值和最大. [思路] 和之前裸的插头DP差不多,只不过现在回路不需要经过所有的格子.所以有以下几个注意点(具体看注释): (1)left和up插头相等的时候,直接更新答案; (2)left和up插头不存在的时候,还要考虑当前格子不取的情况. orz写了半天,感觉被掏空.jpg 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int MA

bzoj 1187: [HNOI2007]神奇游乐园 插头dp

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Status][Discuss] Description 经 历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游 乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个

【BZOJ1187】[HNOI2007]神奇游乐园 插头DP

[BZOJ1187][HNOI2007]神奇游乐园 Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个小格子,每个小格子中就有一个娱乐项目.然而,小P并不喜欢其中的所有娱乐项目,于是,他给每个项目一个满意度.满意度为正时表示小P喜欢这个项目,值越大表示越喜欢.为负时表示他不喜欢

【BZOJ 1187】 [HNOI2007]神奇游乐园

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 706 Solved: 358 [Submit][Status][Discuss] Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个小格

bzoj:1187: [HNOI2007]神奇游乐园

Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个小格子,每个小格子中就有一个娱乐项目.然而,小P并不喜欢其中的所有娱乐项目,于是,他给每个项目一个满意度.满意度为正时表示小P喜欢这个项目,值越大表示越喜欢.为负时表示他不喜欢,这个负数的绝对值越大表示他越不喜欢.为0时表示他对

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

【BZOJ2310】ParkII 插头DP

[BZOJ2310]ParkII Description Hnoi2007-Day1有一道题目 Park:给你一个 m * n 的矩阵,每个矩阵内有个权值V(i,j) (可能为负数),要求找一条回路,使得每个点最多经过一次,并且经过的点权值之和最大,想必大家印象深刻吧. 无聊的小 C 同学把这个问题稍微改了一下:要求找一条路径,使得每个点最多经过一次,并且点权值之和最大,如果你跟小 C 一样无聊,就麻烦做一下这个题目吧. Input 第一行 m, n,接下来 m行每行 n 个数即. V( i,j

「总结」插头$dp$

集中做完了插头$dp$ 写一下题解. 一开始学的时候还是挺蒙的. 不过后来站在轮廓线$dp$的角度上来看就简单多了. 其实就是一种联通性$dp$,只不过情况比较多而已了. 本来转移方式有两种.逐行和逐格转移. 不过逐行转移因为分类太多所以被舍弃了. 一般的插头$dp$采用逐格转移. 插头表示已经进入当前格子的状态,而并不是将要进入的状态. 状态的表示方式常见的有两种:最小表示法和括号表示法. 括号表示法不如说是广义括号表示法的特殊一种情况,每个插头也就是左右括号就是表示两个相匹配的回路部分,而最

初探插头dp

开学那个月学了点新东西,不知道还记不记得了,mark一下 感觉cdq的论文讲的很详细 题主要跟着kuangbin巨做了几道基础的 http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html 还有几道没做,留着坑 感觉广义括号表示法虽然神奇,但一般最小表示法就够用了吧,感觉最小表示法更直观一点 hdu1693 1 #include<cstdio> 2 #include<iostream> 3 #include<