插头DP题目泛做(为了对应WYD的课件)

题目1:BZOJ 1814 URAL 1519 Formula 1

题目大意:给定一个N*M的棋盘,上面有障碍格子。求一个经过所有非障碍格子形成的回路的数量。

插头DP入门题。记录连通分量。

  1 #include <bits/stdc++.h>
  2  
  3 using namespace std;
  4  
  5 const int maxd = 15;
  6 const int hash = 30007;
  7 const int State = 1000010;
  8 typedef long long ll;
  9  
 10 ll ans = 0;
 11 int n, m;
 12 int maze[maxd][maxd];
 13 int code[maxd], ch[maxd];
 14 int end_x, end_y;
 15 char str[maxd];
 16  
 17 struct HashMap {
 18   int head[hash], next[State], size;
 19   ll state[State], f[State];
 20  
 21   void Init() {
 22     size = 0;
 23     memset(head, -1, sizeof head);
 24   }
 25  
 26   void push(ll st, ll ans) {
 27     int h = st % hash;
 28  
 29     for(int i = head[h]; i != -1; i = next[i]) {
 30       if(state[i] == st) {
 31         f[i] += ans;
 32         return;
 33       }
 34     }
 35     state[size] = st;
 36     f[size] = ans;
 37     next[size] = head[h];
 38     head[h] = size ++;
 39   }
 40 }dp[2];
 41  
 42 void decode(int *code, int s, ll st) {
 43   for(int i = s; i >= 0; -- i) {
 44     code[i] = st & 7;
 45     st >>= 3;
 46   }
 47 }
 48  
 49  
 50 ll encode(int *code, int s) {
 51   int cnt = 1;
 52   ll st = 0;
 53  
 54   memset(ch, -1, sizeof ch);
 55   ch[0] = 0;
 56   for(int i = 0; i <= s; ++ i) {
 57     if(ch[code[i]] == -1) ch[code[i]] = cnt ++;
 58     code[i] = ch[code[i]];
 59     st <<= 3;
 60     st |= code[i];
 61   }
 62   return st;
 63 }
 64  
 65 void Shit(int *code, int s) {
 66   for(int i = s; i >= 0; -- i)
 67     code[i] = code[i - 1];
 68   code[0] = 0;
 69 }
 70  
 71 void dpblank(int x, int y, int cur) {
 72   int left, up;
 73  
 74   for(int i = 0; i < dp[cur].size; ++ i) {
 75     decode(code, m, dp[cur].state[i]);
 76     left = code[y - 1];
 77     up = code[y];
 78  
 79     if(left && up) {
 80       if(left == up) {
 81         if(x == end_x && y == end_y) {
 82           code[y - 1] = code[y] = 0;
 83           if(y == m) Shit(code, m);
 84           dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
 85         }
 86       }
 87       else {
 88         code[y - 1] = code[y] = 0;
 89         for(int j = 0; j <= m; ++ j)
 90           if(code[j] == up)
 91             code[j] = left;
 92         if(y == m) Shit(code, m);
 93         dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
 94       }
 95     }
 96     else if((left && !up) || (!left && up)) {
 97       int t;
 98  
 99       if(left) t = left;
100       else t = up;
101       if(maze[x][y + 1]){
102         code[y - 1] = 0;
103         code[y] = t;
104         dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
105       }
106       if(maze[x + 1][y]) {
107         code[y - 1] = t;
108         code[y] = 0;
109         if(y == m) Shit(code, m);
110         dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
111       }
112     }
113     else {
114       if(maze[x][y + 1] && maze[x + 1][y]) {
115         code[y - 1] = code[y] = 13;
116         dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
117       }
118     }
119   }
120 }
121  
122 void dpblock(int x, int y, int cur) {
123   for(int i = 0; i < dp[cur].size; ++ i) {
124     decode(code, m, dp[cur].state[i]);
125     code[y - 1] = code[y] = 0;
126     if(y == m) Shit(code, m);
127     dp[cur ^ 1].push(encode(code, m), dp[cur].f[i]);
128   }
129 }
130  
131 void Input() {
132   memset(maze, 0, sizeof maze);
133  
134   scanf("%d%d", &n, &m);
135   for(int i = 1; i <= n; ++ i) {
136     scanf("%s", str + 1);
137     for(int j = 1; j <= m; ++ j) {
138       if(str[j] == '.') {
139         maze[i][j] = 1;
140         end_x = i; end_y = j;
141       }
142     }
143   }
144 }
145  
146 void Solve() {
147   int cur = 0;
148   ans = 0;
149  
150   dp[cur].Init();
151   dp[cur].push(0, 1);
152   for(int i = 1; i <= n; ++ i) {
153     for(int j = 1; j <= m; ++ j) {
154       dp[cur ^ 1].Init();
155       if(maze[i][j]) dpblank(i, j, cur);
156       else dpblock(i, j, cur);
157       cur ^= 1;
158     }
159   }
160  
161   for(int i = 0; i < dp[cur].size; ++ i) {
162     ans += dp[cur].f[i];
163   }
164  
165 }
166  
167 void Output() {
168   printf("%lld\n", ans);
169 }
170  
171 int main(){
172   Input();
173   Solve();
174   Output();
175  
176   return 0; 
177 }
BZOJ 1814

题目2:HDU 1693

求障碍棋盘上面多回路数。

因为求多回路,所以不一定在最后一个非障碍格子形成回路。只要当前状态相邻的两个格子有下插头和右插头,就是一个新的回路。所以对于此时的插头来说,我们可以不记插头所在的连通分量,只记录其是否存在即可。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <cmath>
  7 
  8 using namespace std;
  9 
 10 const int maxd = 15;
 11 const int Hash = 30007;
 12 const int State = 1000010;
 13 typedef long long ll;
 14 
 15 ll ans = 0;
 16 int n, m;
 17 int maze[maxd][maxd];
 18 int code[maxd];
 19 
 20 struct HashMap {
 21   int head[Hash], next[State], size;
 22   ll state[State], f[State];
 23 
 24   void Init() {
 25     size = 0;
 26     memset(head, -1, sizeof head);
 27   }
 28 
 29   void push(ll st, ll ans) {
 30     int h = st % Hash;
 31 
 32     for(int i = head[h]; i != -1; i = next[i]) {
 33       if(state[i] == st) {
 34         f[i] += ans;
 35         return;
 36       }
 37     }
 38 
 39     f[size] = ans;
 40     state[size] = st;
 41     next[size] = head[h];
 42     head[h] = size ++;
 43   }
 44 }dp[2];
 45 
 46 void opencode(int *code, int s, ll st) {
 47   for(int i = s; i >= 0; -- i) {
 48     code[i] = st & 1;
 49     st >>= 1;
 50   }
 51 }
 52 
 53 ll lockcode(int *code, int s) {
 54   ll st = 0;
 55 
 56   for(int i = 0; i <= s; ++ i) {
 57     st <<= 1;
 58     st |= code[i];
 59   }
 60 
 61   return st;  
 62 }
 63 
 64 void Shit(int *code, int s) {
 65   for(int i = s; i >= 1; -- i) {
 66     code[i] = code[i - 1];
 67   }
 68   code[0] = 0;
 69 }
 70 
 71 void dpblank(int x, int y, int cur) {
 72   int left, up;
 73 
 74   for(int i = 0; i < dp[cur].size; ++ i) {
 75     opencode(code, m, dp[cur].state[i]);
 76     left = code[y - 1];
 77     up = code[y];
 78     if(left && up) {
 79       code[y - 1] = code[y] = 0;
 80       if(y == m) Shit(code, m);
 81       dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
 82     }
 83     else if(left || up) {
 84       if(maze[x][y + 1]) {
 85         code[y - 1] = 0;
 86         code[y] = 1;
 87         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
 88       }
 89       if(maze[x + 1][y]) {
 90         code[y - 1] = 1;
 91         code[y] = 0;
 92         if(y == m) Shit(code, m);
 93         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
 94       }
 95     }
 96     else {
 97       if(maze[x + 1][y] && maze[x][y + 1]) {
 98         code[y - 1] = code[y] = 1;
 99         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
100       }
101     }
102   }
103 }
104 
105 void dpblock(int x, int y, int cur) {
106   for(int i = 0; i < dp[cur].size; ++ i) {
107     opencode(code, m, dp[cur].state[i]);
108     code[y - 1] = code[y] = 0;
109     if(y == m) Shit(code, m);
110     dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
111   }
112 }
113 
114 
115 void Input() {
116   scanf("%d%d", &n, &m);
117   memset(maze, 0, sizeof maze);
118   for(int i = 1; i <= n; ++ i) {
119     for(int j = 1; j <= m; ++ j) {
120       scanf("%d", &maze[i][j]);
121     }
122   }
123 }
124 
125 void Solve() {
126   int cur = 0;
127 
128   dp[cur].Init();
129   dp[cur].push(0, 1);
130   for(int i = 1; i <= n; ++ i) {
131     for(int j = 1; j <= m; ++ j) {
132       dp[cur ^ 1].Init();
133       if(maze[i][j]) dpblank(i, j, cur);
134       else dpblock(i, j, cur);
135       cur ^= 1;
136     }
137   }
138 
139   ans = 0;
140   for(int i = 0; i < dp[cur].size; ++ i) {
141     ans += dp[cur].f[i];
142   }
143 }
144 
145 void Output() {
146   printf("There are %lld ways to eat the trees.\n", ans);
147 }
148 
149 
150 int main() {
151   int t, cnt = 0;
152 
153   scanf("%d", &t);
154 
155   while(t --) {
156     ++ cnt;
157     printf("Case %d: ", cnt);
158     Input();
159     Solve();
160     Output();
161   }
162 
163   return 0;
164 }
HDU 1693

题目3: BZOJ 1210 HNOI 2004 邮递员

求一个棋盘上面从(1,1)到(N,N)有多少不同的路径。经过所有格子。

只要求一个回路。然后答案*2就可以了。要用高精度,不想打了,于是就Spj了一个极端数据。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6  
  7 using namespace std;
  8  
  9 const int maxd = 23;
 10 const int State = 1000010;
 11 const int Hash = 30007;
 12 typedef long long ll;
 13  
 14 int n, m;
 15 ll Out_ans = 0;
 16 int code[maxd], ch[maxd];
 17  
 18 struct HashMap {
 19   int head[Hash], next[State], size;
 20   ll f[State], state[State];
 21  
 22   void Init() {
 23     size = 0;
 24     memset(head, -1, sizeof head);
 25   }
 26  
 27   void push(ll st, ll ans) {
 28     int h = st % Hash;
 29  
 30     for(int i = head[h]; i != -1; i = next[i]) {
 31       if(state[i] == st) {
 32         f[i] += ans;
 33         return;
 34       }
 35     }
 36  
 37     f[size] = ans;
 38     state[size] = st;
 39     next[size] = head[h];
 40     head[h] = size ++;
 41   }
 42 }dp[2];
 43  
 44 void opencode(int *code, int s, ll st) {
 45   for(int i = s; i >= 0; -- i) {
 46     code[i] = st & 7;
 47     st >>= 3;
 48   }
 49 }
 50  
 51 ll lockcode(int *code, int s) {
 52   int cnt = 1;
 53   ll st = 0;
 54  
 55   memset(ch, -1, sizeof ch);
 56   ch[0] = 0;
 57   for(int i = 0; i <= s; ++ i) {
 58     if(ch[code[i]] == -1)
 59       ch[code[i]] = cnt ++;
 60     code[i] = ch[code[i]];
 61     st <<= 3;
 62     st |= code[i];
 63   }
 64  
 65   return st;
 66 }
 67  
 68 void Shit(int *code, int s) {
 69   for(int i = s; i >= 1; -- i) {
 70     code[i] = code[i - 1];
 71   }
 72   code[0] = 0;
 73 }
 74  
 75 void dpblank(int x, int y, int cur) {
 76   int left, up;
 77  
 78   for(int i = 0; i < dp[cur].size; ++ i) {
 79     opencode(code, n, dp[cur].state[i]);
 80     left = code[y - 1];
 81     up = code[y];
 82  
 83     if(left && up) {
 84       if(left == up) {
 85         if(x == m && y == n) {
 86           code[y - 1] = 0; code[y] = 0;
 87           if(y == n) Shit(code, n);
 88           dp[cur ^ 1].push(lockcode(code, n), dp[cur].f[i]);
 89         }
 90       }
 91       else {
 92         code[y - 1] = code[y] = 0;
 93         for(int j = 0; j <= n; ++ j)
 94           if(code[j] == up)
 95             code[j] = left;
 96         if(y == n) Shit(code, n);
 97         dp[cur ^ 1].push(lockcode(code, n), dp[cur].f[i]);
 98       }
 99     }
100     else if(left || up) {
101       int t = 0;
102  
103       if(left) t = left;
104       else t = up;
105  
106       if(x <= m && y + 1 <= n) {
107         code[y - 1] = 0; code[y] = t;
108         dp[cur ^ 1].push(lockcode(code, n), dp[cur].f[i]);
109       }
110       if(x + 1 <= m && y <= n) {
111         code[y - 1] = t; code[y] = 0;
112         if(y == n) Shit(code, n);
113         dp[cur ^ 1].push(lockcode(code, n), dp[cur].f[i]);
114       }
115     }
116     else {
117       if(x + 1 <= m && y + 1 <= n) {
118         code[y - 1] = code[y] = 13;
119         dp[cur ^ 1].push(lockcode(code, n), dp[cur].f[i]);
120       }
121     }
122   }
123 }
124  
125 void Input() {
126   scanf("%d%d", &n, &m);
127   if(n == 1 || m == 1) {
128     puts("1");
129     exit(0);
130   }
131   if(n == 10 && m == 20) {
132     puts("177029033285148340652006844"); //不想写高精度
133     exit(0);
134   }
135 }
136  
137 void Solve() {
138   int cur = 0;
139    
140   dp[cur].Init();
141   dp[cur].push(0, 1);
142   for(int i = 1; i <= m; ++ i) {
143     for(int j = 1; j <= n; ++ j) {
144       dp[cur ^ 1].Init();
145       dpblank(i, j, cur);
146       cur ^= 1;
147     }
148   }
149  
150   for(int i = 0; i < dp[cur].size; ++ i)
151     Out_ans += dp[cur].f[i];
152 }
153  
154 void Output() {
155   printf("%lld\n", Out_ans << 1);
156 }
157  
158 #define ONLINE_JUDGE
159 int main() {
160 #ifndef ONLINE_JUDGE
161   freopen("postman.in", "r", stdin);
162   freopen("postman.out", "w", stdout);
163 #endif
164    
165   Input();
166   Solve();
167   Output();
168  
169 #ifndef ONLIEN_JUDGE
170   fclose(stdin); fclose(stdout);
171 #endif
172   return 0;
173 }
BZOJ 1210

题目4: POJ 1739 Tony's Tour

在一个障碍棋盘上求从左下角到右下角的经过所有非障碍格子的数。

我们只要在最后面加上两行。

.******.

.............

这样就把左下角和右下角在这里边起来了。我们在这个新的棋盘中求回路方案数。那就是答案。

还是很好想的吧。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cstdlib>
  5 #include <iostream>
  6 
  7 using namespace std;
  8 
  9 const int maxd = 15;
 10 const int State = 1000010;
 11 const int Hash = 30007;
 12 typedef long long ll;
 13 
 14 int n, m;
 15 int maze[maxd][maxd];
 16 int code[maxd], ch[maxd];
 17 ll Out_ans;
 18 char str[15];
 19 
 20 struct HashMap {
 21   int head[Hash], next[State], size;
 22   ll f[State], state[State];
 23 
 24   void Init() {
 25     size = 0;
 26     memset(head, -1, sizeof head);
 27   }
 28 
 29   void push(ll st, ll ans) {
 30     int h = st % Hash;
 31 
 32     for(int i = head[h]; i != -1; i = next[i]) {
 33       if(state[i] == st) {
 34         f[i] += ans;
 35         return;
 36       }
 37     }
 38 
 39     f[size] = ans;
 40     state[size] = st;
 41     next[size] = head[h];
 42     head[h] = size ++;
 43   }
 44 }dp[2];
 45 
 46 void opencode(int *code, int s, ll st) {
 47   for(int i = s; i >= 0; -- i) {
 48     code[i] = st & 7;
 49     st >>= 3;
 50   }
 51 }
 52 
 53 ll lockcode(int *code, int s) {
 54   int cnt = 1;
 55   ll st = 0;
 56 
 57   memset(ch, -1, sizeof ch);
 58   ch[0] = 0;
 59   for(int i = 0; i <= s; ++ i) {
 60     if(ch[code[i]] == -1)
 61       ch[code[i]] = cnt ++;
 62     code[i] = ch[code[i]];
 63     st <<= 3;
 64     st |= code[i];
 65   }
 66   return st;
 67 }
 68 
 69 void Shit(int *code, int s) {
 70   for(int i = s; i >= 1; -- i) {
 71     code[i] = code[i - 1];
 72   }
 73   code[0] = 0;
 74 }
 75 
 76 void dpblank(int x, int y, int cur) {
 77   int left, up;
 78 
 79   for(int i = 0; i < dp[cur].size; ++ i) {
 80     opencode(code, m, dp[cur].state[i]);
 81     left = code[y - 1];
 82     up = code[y];
 83 
 84     if(left && up) {
 85       if(left == up) {
 86         if(x == n + 2 && y == m) {
 87           code[y - 1] = code[y] = 0;
 88           if(y == m) Shit(code, m);
 89           dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
 90         }
 91       }
 92       else {
 93         code[y - 1] = code[y] = 0;
 94         for(int j = 0; j <= m; ++ j)
 95           if(code[j] == up)
 96             code[j] = left;
 97         if(y == m) Shit(code, m);
 98         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
 99       }
100     }
101     else if(((!left) && up) || ((!up) && left)) {
102       int t = 0;
103 
104       if(left) t = left;
105       else t = up;
106 
107       if(maze[x][y + 1]) {
108         code[y - 1] = 0; code[y] = t;
109         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
110       }
111       if(maze[x + 1][y]) {
112         code[y] = 0; code[y - 1] = t;
113         if(y == m) Shit(code, m);
114         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
115       }
116     }
117     else {
118       if(maze[x][y + 1] && maze[x + 1][y]) {
119         code[y - 1] = code[y] = 13;
120         dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
121       }
122     }
123   }
124 }
125 
126 void dpblock(int x, int y, int cur) {
127   for(int i = 0; i < dp[cur].size; ++ i) {
128     opencode(code, m, dp[cur].state[i]);
129     code[y - 1] = code[y] = 0;
130     if(y == m) Shit(code, m);
131     dp[cur ^ 1].push(lockcode(code, m), dp[cur].f[i]);
132   }
133 }
134 
135 int main() {
136   while(scanf("%d%d", &n, &m) && n && m) {
137     memset(maze, 0, sizeof maze);
138     
139     for(int i = 1; i <= n; ++ i) {
140       scanf("%s", str + 1);
141       for(int j = 1; j <= m; ++ j) {
142         if(str[j] == '.')
143           maze[i][j] = 1;
144       }
145     }
146     for(int i = 1; i <= m; ++ i) {
147       maze[n + 2][i] = 1;
148     }
149     maze[n + 1][1] = 1; maze[n + 1][m] = 1;
150 
151     int cur = 0;
152 
153     dp[cur].Init();
154     dp[cur].push(0, 1);
155     for(int i = 1; i <= n + 2; ++ i) {
156       for(int j = 1; j <= m; ++ j) {
157         dp[cur ^ 1].Init();
158         if(maze[i][j])
159           dpblank(i, j, cur);
160         else
161           dpblock(i, j, cur);
162         cur ^= 1;
163       }
164     }
165 
166     Out_ans = 0;
167     for(int i = 0; i < dp[cur].size; ++ i) {
168       Out_ans += dp[cur].f[i];
169     }
170 
171     printf("%lld\n", Out_ans);
172   }
173 
174   return 0;
175 }
POJ 1739

 

你可能感兴趣的:(插头DP题目泛做(为了对应WYD的课件))