【插头DP】HDU 3377 Plan

通道:http://acm.hdu.edu.cn/showproblem.php?pid=3377

题意:简单路径,从左上角走到右下角的最大权值,不需要每个格子都需要经过。

思路:初始化左上角上面那一格有下插头,然后一个不选状态,over.

代码:

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

 

转载于:https://www.cnblogs.com/Rojo/p/4640692.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值