通道:http://poj.org/problem?id=3133
题意:2条简单路径,不相交,最小权值,可选可不选,有障碍。
思路:构造2条轮廓线分辨表示两条路径即可。
代码:
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] = min(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 int a[MAX_N][MAX_M]; 35 36 int find_pos(long long s, int p) { 37 return s >> mov[p] & 3; 38 } 39 40 void tp(long long &s, int p, long long v) { 41 s &= ~(3ll << mov[p]); 42 s |= v << mov[p]; 43 } 44 45 46 int find_r(long long s, int p) { 47 int cnt = 0; 48 for(int i = p; i <= m; ++i) { 49 if(find_pos(s, i) == 1) ++cnt; 50 else if(find_pos(s, i) == 2) --cnt; 51 if(!cnt) return i; 52 } 53 } 54 55 int find_l(long long s, int p) { 56 int cnt = 0; 57 for(int i = p; i >= 0; --i) { 58 if(find_pos(s, i) == 2) ++cnt; 59 else if(find_pos(s, i) == 1) --cnt; 60 if(!cnt) return i; 61 } 62 } 63 64 void blank(int i, int j, int cur) { 65 for(int k = 0; k < d[cur].cnt; ++k) { 66 long long t = d[cur].st[k]; 67 int l = find_pos(t, j - 1), r = find_pos(t, j); 68 if (a[i][j] >= 2) { 69 if (l && r) continue; 70 int now = a[i][j] == 2 ? 1 : 2; 71 if (!l && !r) { 72 if (i < n) { 73 tp(t, j - 1, now); tp(t, j, 0); 74 d[cur ^ 1].push(t, d[cur].dp[k]); 75 } 76 if (j < m) { 77 t = d[cur].st[k]; 78 tp(t, j - 1, 0); tp(t, j, now); 79 d[cur ^ 1].push(t, d[cur].dp[k]); 80 } 81 } else { 82 if (l + r != now) continue; 83 tp(t, j - 1, 0); tp(t, j, 0); 84 d[cur ^ 1].push(t, d[cur].dp[k]); 85 } 86 continue; 87 } 88 if(l && r) { 89 if (l != r) continue; 90 tp(t, j - 1, 0); tp(t, j, 0); 91 d[cur ^ 1].push(t, d[cur].dp[k] + 1); 92 } else if(l || r) { 93 int now = l + r; 94 if(i < n) { 95 tp(t, j - 1, now); tp(t, j, 0); 96 d[cur ^ 1].push(t, d[cur].dp[k] + 1); 97 } 98 if(j < m) { 99 t = d[cur].st[k]; 100 tp(t, j - 1, 0); tp(t, j, now); 101 d[cur ^ 1].push(t, d[cur].dp[k] + 1); 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, 1); 107 d[cur ^ 1].push(t, d[cur].dp[k] + 1); 108 t = d[cur].st[k]; 109 tp(t, j - 1, 2); tp(t, j, 2); 110 d[cur ^ 1].push(t, d[cur].dp[k] + 1); 111 } 112 } 113 } 114 } 115 116 void block(int i, int j, int cur) { 117 for (int k = 0; k < d[cur].cnt; ++k) { 118 long long t = d[cur].st[k]; 119 int l = find_pos(t, j - 1), r = find_pos(t, j); 120 if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k]); 121 } 122 } 123 124 int main() { 125 while (2 == scanf("%d%d", &n, &m)) { 126 if (0 == n && 0 == m) break; 127 memset(a, 0, sizeof a); 128 for (int i = 1; i <= n; ++i) 129 for (int j = 1; j <= m; ++j) 130 scanf("%d", &a[i][j]); 131 int cur = 0; 132 d[cur].init(); 133 d[cur].push(0, 0); 134 for (int i = 1; i <= n; ++i) { 135 for (int j = 1; j <= m; ++j) { 136 d[cur ^ 1].init(); 137 if (a[i][j] == 1) block(i, j, cur); 138 else blank(i, j, cur); 139 cur ^= 1; 140 } 141 for (int j = 0; j < d[cur].cnt; ++j) 142 d[cur].st[j] <<= 2; 143 } 144 int ans = (int) 1e9; 145 for (int i = 0; i < d[cur].cnt; ++i) 146 ans = min((long long)ans, d[cur].dp[i]); 147 if (ans == (int)1e9) puts("0"); 148 else printf("%d\n", ans + 2); 149 } 150 return 0; 151 }