hdu 3338 Kakuro Extension
http://acm.hdu.edu.cn/showproblem.php?pid=3338构图我也不废话了,有人说了怎么构
详见http://www.cnblogs.com/ylfdrib/archive/2010/08/15/1799903.html
我只贴代码,最好自己写, 懂了构图,完全可以看懂我的代码。
1
//
算法实现:ISAP算法(邻接表实现)
2 #include < iostream >
3 #include < cstdio >
4 #include < cstring >
5 #define M 121
6 using namespace std;
7 const int maxn = 13201 ;
8 const int maxm = 200001 ;
9
10 struct Edge{
11
12 int flag;
13 int i, j;
14 }ee[maxn];
15
16 struct node {
17 // x起点,y终点,f容量,next是以x为起点的上一条边在g中的位置,op是反向边在g中的下标位置
18 int x, y, f, op, next;
19 }g[maxm * 2 ];
20
21 char mat[ M ][ M ][ 10 ];
22 char ans[ M ][ M ];
23 int a[ M ][ M ], va[ M ][ M ];
24 int c[ M ][ M ], vc[ M ][ M ];
25 int b[ M ][ M ];
26 int m, n, S, E, aid, ccc;
27
28 // first[]存储的是以x为起点的最后一条边的在数组g中的下标
29 // sumd[]用于记录表示标号为i的顶点数有多少个,用于间隙优化
30 // now[]临时记录以x为起点的最后一条边在数组g中的下标
31 int first[maxn],now[maxn],sumd[maxn];
32 int ncount; // 代表结点的总数
33 int dis[maxn],fanhui[maxn],pre[maxn],tot; // dis[]用于记录距离标号,pre[i]记录i的前驱在g[]中的位置,tot记录边的总数
34
35 void insert( int x, int y, int c) {
36
37 tot ++ ; // tot记录边的总数
38 g[tot].x = x;
39 g[tot].y = y;
40 g[tot].f = c;
41 g[tot].op = tot + 1 ; // 反向边在g中的下标位置
42 g[tot].next = first[x]; // 记录以x为起点的上一条边在g中的下标位置
43 first[x] = tot; // 以x为起点的边的位置
44 tot ++ ;
45 // 反向边
46 g[tot].x = y;
47 g[tot].y = x;
48 g[tot].f = 0 ; // 反向边的初始网络流为0
49 g[tot].op = tot - 1 ;
50 g[tot].next = first[y];
51 first[y] = tot;
52 }
53 // ISAP算法
54 int maxflow( int src, int des) {
55
56 int i,flow,t,j,tempmin; // i,j用于标识结点,t用于标识结点在g中的位置
57 bool flag; // 用于标识是否找到了允许路径
58 int sumFlow;
59 memset(dis, 0 , sizeof (dis)); // 初始化dis为0
60 memset(sumd, 0 , sizeof (sumd));
61 for (i = 1 ;i <= ncount;i ++ )
62 now[i] = first[i];
63 sumd[ 0 ] = ncount; // 标号为0的结点有ncount个
64 sumFlow = 0 ; // sumFlow记录最大流,初始化为0
65 i = src; // i初始化为起点
66 flow = 10000000 ;
67 while (dis[src] < ncount)
68 {
69 fanhui[i] = flow;
70 flag = false ;
71 t = now[i];
72 while (t != 0 ) // 寻找允许路径
73 {
74 j = g[t].y;
75 if ((g[t].f > 0 ) && (dis[j] + 1 == dis[i])) // 允许弧
76 {
77 flag = true ;
78 pre[j] = t;
79 now[i] = t;
80 if (g[t].f < flow) // 找到允许增量
81 flow = g[t].f;
82 i = j;
83 if (i == ncount) // 找到了允许路径
84 {
85 sumFlow += flow;
86 while (i != src) // 修改残余网络
87 {
88 g[pre[i]].f -= flow; // 正向边
89 g[g[pre[i]].op].f += flow; // 反向边
90 i = g[pre[i]].x;
91 }
92 flow = 10000000 ;
93 }
94 break ;
95 }
96 t = g[t].next;
97 }
98 if (flag)
99 continue ;
100 // 没有找到允许路径
101 tempmin = ncount - 1 ;
102 t = first[i];
103 while (t != 0 )
104 {
105 if ((g[t].f > 0 ) && (dis[g[t].y] < tempmin))
106 {
107 tempmin = dis[g[t].y];
108 now[i] = t;
109 }
110 t = g[t].next;
111 }
112 sumd[dis[i]] -- ;
113 if (sumd[dis[i]] == 0 ) break ; // 间隙优化
114 dis[i] = tempmin + 1 ; // 此处别忘+1,因为d[i]=tempmin{d[j]+1|(i,j)在残留网络中}
115 sumd[dis[i]] ++ ;
116 if (i != src)
117 {
118 i = g[pre[i]].x;
119 flow = fanhui[i];
120 }
121 }
122 return sumFlow;
123 }
124
125 void solve( int i, int j) {
126
127 char str[ 10 ];
128 strcpy(str, mat[ i ][ j ]);
129
130 if (str[ 0 ] != ' X ' && str[ 6 ] != ' X ' ) {
131
132 int k;
133
134 c[ i ][ j ] = aid ++ ;
135 vc[ i ][ j ] = 0 ;
136 for (k = 0 ; k < 3 ; ++ k) {
137
138 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
139
140 vc[ i ][ j ] = vc[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
141 }
142 }
143
144 a[ i ][ j ] = aid ++ ;
145 va[ i ][ j ] = 0 ;
146 for (k = 4 ;k < 7 ; ++ k) {
147
148 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
149
150 va[ i ][ j ] = va[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
151 }
152 }
153 }
154 else if (str[ 0 ] != ' X ' ) {
155
156 vc[ i ][ j ] = 0 ;
157 for ( int k = 0 ; k < 3 ; ++ k) {
158
159 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
160
161 vc[ i ][ j ] = vc[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
162 }
163 }
164 c[ i ][ j ] = aid ++ ;
165 }
166 else {
167
168 va[ i ][ j ] = 0 ;
169 a[ i ][ j ] = aid ++ ;
170
171 for ( int k = 4 ;k < 7 ; ++ k) {
172
173 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
174
175 va[ i ][ j ] = va[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
176 }
177 }
178 }
179 }
180
181
182 void print( int p[][ 101 ]) {
183
184 for ( int i = 1 ; i <= m; ++ i) {
185
186 for ( int j = 1 ; j <= n; ++ j)
187 printf( " %3d " , p[ i ][ j ]);
188 cout << endl;
189 }
190 cout << endl;
191 }
192
193 void init() {
194
195 aid = 1 ;
196 char str[ 10 ];
197 int i, j;
198
199 for (i = 1 ; i <= m; ++ i) {
200
201 for (j = 1 ; j <= n; ++ j) {
202
203 va[ i ][ j ] = - 1 ; // va,vc先不要赋值0,否则像我一样杯具30次
204 vc[ i ][ j ] = - 1 ;
205 a[ i ][ j ] = - 1 ;
206 b[ i ][ j ] = - 1 ;
207 c[ i ][ j ] = - 1 ;
208
209 strcpy(str, mat[ i ][ j ]);
210
211 if (str[ 0 ] != ' . ' ) {
212
213 ans[ i ][ j ] = ' _ ' ;
214 if (str[ 0 ] != ' X ' || str[ 6 ] != ' X ' )
215 solve(i, j);
216 }
217 else {
218
219 b[ i ][ j ] = aid ++ ;
220 }
221 }
222 }
223
224 // print(va);
225 // print(vc);
226
227 for (i = 1 ; i <= m; ++ i) {
228
229 for (j = 1 ; j <= n; ++ j) {
230
231 if (va[ i ][ j ] != - 1 ) {
232
233 int csd = 0 ;
234 for ( int k = j + 1 ; k <= n && mat[ i ][ k ][ 0 ] == ' . ' ; ++ k) {
235
236 csd ++ ;
237 }
238 va[ i ][ j ] -= csd;
239 }
240
241 if (vc[ i ][ j ] != - 1 ) {
242
243 int csd = 0 ;
244 for ( int k = i + 1 ; k <= m && mat[ k ][ j ][ 0 ] == ' . ' ; ++ k) {
245
246 csd ++ ;
247 }
248 vc[ i ][ j ] -= csd;
249 }
250 }
251 }
252
253 // print(va);
254 // print(vc);
255
256 for (i = 1 ; i <= m; ++ i) {
257
258 for (j = 1 ; j <= n; ++ j) {
259
260 if (i > 1 ) {
261
262 if (vc[ i ][ j ] == - 1 && vc[i - 1 ][ j ] != - 1 ) {
263
264 c[ i ][ j ] = c[i - 1 ][ j ];
265 vc[ i ][ j ] = vc[i - 1 ][ j ];
266 }
267 }
268
269 if (j > 1 ) {
270
271 if (va[ i ][ j ] == - 1 && va[ i ][j - 1 ] != - 1 ) {
272
273 a[ i ][ j ] = a[ i ][j - 1 ];
274 va[ i ][ j ] = va[ i ][j - 1 ];
275 }
276 }
277 }
278 // cout << endl;
279 }
280
281 ccc = 0 ;
282 tot = 0 ;
283 S = aid, E = aid + 1 ;
284 ncount = E;
285
286 memset(first, 0 , sizeof (first));
287
288
289 // print(a);
290 // print(b);
291 // print(c);
292 // print(va);
293 // print(vc);
294
295 // cout << aid << endl;
296 }
297
298 void printRes() {
299
300 for ( int i = 1 ; i <= m; ++ i) {
301
302 for ( int j = 1 ; j < n; ++ j) {
303
304 printf( " %c " , ans[ i ][ j ]);
305 }
306 printf( " %c\n " , ans[ i ][ j ]);
307 }
308 }
309
310
311 int main() {
312
313 int i, j;
314 while (scanf( " %d %d " , & m, & n) == 2 ) {
315
316 for (i = 1 ;i <= m; ++ i) {
317
318 for (j = 1 ; j <= n; ++ j) {
319
320 scanf( " %s " , mat[ i ][ j ]);
321 }
322 }
323
324 init();
325
326 bool aa[ maxn ];
327 for (i = 1 ; i <= ncount; ++ i)
328 aa[ i ] = false ;
329
330
331 for (i = 1 ;i <= m; ++ i) {
332
333 for (j = 1 ; j <= n; ++ j) {
334
335 if (b[ i ][ j ] != - 1 ) {
336
337 if ( ! aa[a[i][j]]) {
338
339 insert(S, a[i][j], va[i][j]);
340 aa[a[i][j]] = true ;
341 }
342
343 insert(a[i][j], b[i][j], 8 );
344
345 ee[ccc].flag = tot;
346 ee[ccc].i = i;
347 ee[ccc].j = j;
348 ccc ++ ;
349
350 insert(b[i][j], c[i][j], 8 );
351
352 if ( ! aa[c[i][j]]) {
353
354 insert(c[i][j], E, vc[i][j]);
355 aa[c[i][j]] = true ;
356 }
357 }
358 }
359 }
360
361 maxflow(S, E);
362
363 for (i = 0 ; i < ccc ; ++ i) {
364
365 int val = g[ee[ i ].flag].f;
366 int loci = ee[ i ].i;
367 int locj = ee[ i ].j;
368
369 ans[ loci ][ locj ] = val + ' 1 ' ;
370 }
371
372 printRes();
373 }
374 return 0 ;
375 }
376
2 #include < iostream >
3 #include < cstdio >
4 #include < cstring >
5 #define M 121
6 using namespace std;
7 const int maxn = 13201 ;
8 const int maxm = 200001 ;
9
10 struct Edge{
11
12 int flag;
13 int i, j;
14 }ee[maxn];
15
16 struct node {
17 // x起点,y终点,f容量,next是以x为起点的上一条边在g中的位置,op是反向边在g中的下标位置
18 int x, y, f, op, next;
19 }g[maxm * 2 ];
20
21 char mat[ M ][ M ][ 10 ];
22 char ans[ M ][ M ];
23 int a[ M ][ M ], va[ M ][ M ];
24 int c[ M ][ M ], vc[ M ][ M ];
25 int b[ M ][ M ];
26 int m, n, S, E, aid, ccc;
27
28 // first[]存储的是以x为起点的最后一条边的在数组g中的下标
29 // sumd[]用于记录表示标号为i的顶点数有多少个,用于间隙优化
30 // now[]临时记录以x为起点的最后一条边在数组g中的下标
31 int first[maxn],now[maxn],sumd[maxn];
32 int ncount; // 代表结点的总数
33 int dis[maxn],fanhui[maxn],pre[maxn],tot; // dis[]用于记录距离标号,pre[i]记录i的前驱在g[]中的位置,tot记录边的总数
34
35 void insert( int x, int y, int c) {
36
37 tot ++ ; // tot记录边的总数
38 g[tot].x = x;
39 g[tot].y = y;
40 g[tot].f = c;
41 g[tot].op = tot + 1 ; // 反向边在g中的下标位置
42 g[tot].next = first[x]; // 记录以x为起点的上一条边在g中的下标位置
43 first[x] = tot; // 以x为起点的边的位置
44 tot ++ ;
45 // 反向边
46 g[tot].x = y;
47 g[tot].y = x;
48 g[tot].f = 0 ; // 反向边的初始网络流为0
49 g[tot].op = tot - 1 ;
50 g[tot].next = first[y];
51 first[y] = tot;
52 }
53 // ISAP算法
54 int maxflow( int src, int des) {
55
56 int i,flow,t,j,tempmin; // i,j用于标识结点,t用于标识结点在g中的位置
57 bool flag; // 用于标识是否找到了允许路径
58 int sumFlow;
59 memset(dis, 0 , sizeof (dis)); // 初始化dis为0
60 memset(sumd, 0 , sizeof (sumd));
61 for (i = 1 ;i <= ncount;i ++ )
62 now[i] = first[i];
63 sumd[ 0 ] = ncount; // 标号为0的结点有ncount个
64 sumFlow = 0 ; // sumFlow记录最大流,初始化为0
65 i = src; // i初始化为起点
66 flow = 10000000 ;
67 while (dis[src] < ncount)
68 {
69 fanhui[i] = flow;
70 flag = false ;
71 t = now[i];
72 while (t != 0 ) // 寻找允许路径
73 {
74 j = g[t].y;
75 if ((g[t].f > 0 ) && (dis[j] + 1 == dis[i])) // 允许弧
76 {
77 flag = true ;
78 pre[j] = t;
79 now[i] = t;
80 if (g[t].f < flow) // 找到允许增量
81 flow = g[t].f;
82 i = j;
83 if (i == ncount) // 找到了允许路径
84 {
85 sumFlow += flow;
86 while (i != src) // 修改残余网络
87 {
88 g[pre[i]].f -= flow; // 正向边
89 g[g[pre[i]].op].f += flow; // 反向边
90 i = g[pre[i]].x;
91 }
92 flow = 10000000 ;
93 }
94 break ;
95 }
96 t = g[t].next;
97 }
98 if (flag)
99 continue ;
100 // 没有找到允许路径
101 tempmin = ncount - 1 ;
102 t = first[i];
103 while (t != 0 )
104 {
105 if ((g[t].f > 0 ) && (dis[g[t].y] < tempmin))
106 {
107 tempmin = dis[g[t].y];
108 now[i] = t;
109 }
110 t = g[t].next;
111 }
112 sumd[dis[i]] -- ;
113 if (sumd[dis[i]] == 0 ) break ; // 间隙优化
114 dis[i] = tempmin + 1 ; // 此处别忘+1,因为d[i]=tempmin{d[j]+1|(i,j)在残留网络中}
115 sumd[dis[i]] ++ ;
116 if (i != src)
117 {
118 i = g[pre[i]].x;
119 flow = fanhui[i];
120 }
121 }
122 return sumFlow;
123 }
124
125 void solve( int i, int j) {
126
127 char str[ 10 ];
128 strcpy(str, mat[ i ][ j ]);
129
130 if (str[ 0 ] != ' X ' && str[ 6 ] != ' X ' ) {
131
132 int k;
133
134 c[ i ][ j ] = aid ++ ;
135 vc[ i ][ j ] = 0 ;
136 for (k = 0 ; k < 3 ; ++ k) {
137
138 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
139
140 vc[ i ][ j ] = vc[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
141 }
142 }
143
144 a[ i ][ j ] = aid ++ ;
145 va[ i ][ j ] = 0 ;
146 for (k = 4 ;k < 7 ; ++ k) {
147
148 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
149
150 va[ i ][ j ] = va[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
151 }
152 }
153 }
154 else if (str[ 0 ] != ' X ' ) {
155
156 vc[ i ][ j ] = 0 ;
157 for ( int k = 0 ; k < 3 ; ++ k) {
158
159 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
160
161 vc[ i ][ j ] = vc[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
162 }
163 }
164 c[ i ][ j ] = aid ++ ;
165 }
166 else {
167
168 va[ i ][ j ] = 0 ;
169 a[ i ][ j ] = aid ++ ;
170
171 for ( int k = 4 ;k < 7 ; ++ k) {
172
173 if (str[ k ] >= ' 0 ' && str[ k ] <= ' 9 ' ) {
174
175 va[ i ][ j ] = va[ i ][ j ] * 10 + str[ k ] - ' 0 ' ;
176 }
177 }
178 }
179 }
180
181
182 void print( int p[][ 101 ]) {
183
184 for ( int i = 1 ; i <= m; ++ i) {
185
186 for ( int j = 1 ; j <= n; ++ j)
187 printf( " %3d " , p[ i ][ j ]);
188 cout << endl;
189 }
190 cout << endl;
191 }
192
193 void init() {
194
195 aid = 1 ;
196 char str[ 10 ];
197 int i, j;
198
199 for (i = 1 ; i <= m; ++ i) {
200
201 for (j = 1 ; j <= n; ++ j) {
202
203 va[ i ][ j ] = - 1 ; // va,vc先不要赋值0,否则像我一样杯具30次
204 vc[ i ][ j ] = - 1 ;
205 a[ i ][ j ] = - 1 ;
206 b[ i ][ j ] = - 1 ;
207 c[ i ][ j ] = - 1 ;
208
209 strcpy(str, mat[ i ][ j ]);
210
211 if (str[ 0 ] != ' . ' ) {
212
213 ans[ i ][ j ] = ' _ ' ;
214 if (str[ 0 ] != ' X ' || str[ 6 ] != ' X ' )
215 solve(i, j);
216 }
217 else {
218
219 b[ i ][ j ] = aid ++ ;
220 }
221 }
222 }
223
224 // print(va);
225 // print(vc);
226
227 for (i = 1 ; i <= m; ++ i) {
228
229 for (j = 1 ; j <= n; ++ j) {
230
231 if (va[ i ][ j ] != - 1 ) {
232
233 int csd = 0 ;
234 for ( int k = j + 1 ; k <= n && mat[ i ][ k ][ 0 ] == ' . ' ; ++ k) {
235
236 csd ++ ;
237 }
238 va[ i ][ j ] -= csd;
239 }
240
241 if (vc[ i ][ j ] != - 1 ) {
242
243 int csd = 0 ;
244 for ( int k = i + 1 ; k <= m && mat[ k ][ j ][ 0 ] == ' . ' ; ++ k) {
245
246 csd ++ ;
247 }
248 vc[ i ][ j ] -= csd;
249 }
250 }
251 }
252
253 // print(va);
254 // print(vc);
255
256 for (i = 1 ; i <= m; ++ i) {
257
258 for (j = 1 ; j <= n; ++ j) {
259
260 if (i > 1 ) {
261
262 if (vc[ i ][ j ] == - 1 && vc[i - 1 ][ j ] != - 1 ) {
263
264 c[ i ][ j ] = c[i - 1 ][ j ];
265 vc[ i ][ j ] = vc[i - 1 ][ j ];
266 }
267 }
268
269 if (j > 1 ) {
270
271 if (va[ i ][ j ] == - 1 && va[ i ][j - 1 ] != - 1 ) {
272
273 a[ i ][ j ] = a[ i ][j - 1 ];
274 va[ i ][ j ] = va[ i ][j - 1 ];
275 }
276 }
277 }
278 // cout << endl;
279 }
280
281 ccc = 0 ;
282 tot = 0 ;
283 S = aid, E = aid + 1 ;
284 ncount = E;
285
286 memset(first, 0 , sizeof (first));
287
288
289 // print(a);
290 // print(b);
291 // print(c);
292 // print(va);
293 // print(vc);
294
295 // cout << aid << endl;
296 }
297
298 void printRes() {
299
300 for ( int i = 1 ; i <= m; ++ i) {
301
302 for ( int j = 1 ; j < n; ++ j) {
303
304 printf( " %c " , ans[ i ][ j ]);
305 }
306 printf( " %c\n " , ans[ i ][ j ]);
307 }
308 }
309
310
311 int main() {
312
313 int i, j;
314 while (scanf( " %d %d " , & m, & n) == 2 ) {
315
316 for (i = 1 ;i <= m; ++ i) {
317
318 for (j = 1 ; j <= n; ++ j) {
319
320 scanf( " %s " , mat[ i ][ j ]);
321 }
322 }
323
324 init();
325
326 bool aa[ maxn ];
327 for (i = 1 ; i <= ncount; ++ i)
328 aa[ i ] = false ;
329
330
331 for (i = 1 ;i <= m; ++ i) {
332
333 for (j = 1 ; j <= n; ++ j) {
334
335 if (b[ i ][ j ] != - 1 ) {
336
337 if ( ! aa[a[i][j]]) {
338
339 insert(S, a[i][j], va[i][j]);
340 aa[a[i][j]] = true ;
341 }
342
343 insert(a[i][j], b[i][j], 8 );
344
345 ee[ccc].flag = tot;
346 ee[ccc].i = i;
347 ee[ccc].j = j;
348 ccc ++ ;
349
350 insert(b[i][j], c[i][j], 8 );
351
352 if ( ! aa[c[i][j]]) {
353
354 insert(c[i][j], E, vc[i][j]);
355 aa[c[i][j]] = true ;
356 }
357 }
358 }
359 }
360
361 maxflow(S, E);
362
363 for (i = 0 ; i < ccc ; ++ i) {
364
365 int val = g[ee[ i ].flag].f;
366 int loci = ee[ i ].i;
367 int locj = ee[ i ].j;
368
369 ans[ loci ][ locj ] = val + ' 1 ' ;
370 }
371
372 printRes();
373 }
374 return 0 ;
375 }
376