1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 30078  Solved: 7908
[Submit][Status][Discuss]

Description

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

 BZOJ1001: [BeiJing2006]狼抓兔子(优化的dinic或转化对偶图求最短路)

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
1:(x,y)<==>(x+1,y) 
2:(x,y)<==>(x,y+1) 
3:(x,y)<==>(x+1,y+1) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6

Sample Output

14

HINT

 

 2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

 

Source

 
[Submit][Status][Discuss]


HOME Back

题解1(网络流最大流dinic):

题意是求一个无向图的最小割,然后我们运用最小割-最大流定理,可以转化成求最大流的问题。不过朴素的Dinic是会TLE的,这里提供一种优化方法:

我们知道,假定在一次dinic过程中,发现不能再进行增广了,那么就相当于向下的这条路是废的。因此,我们可以直接把这条路堵上,然后就可以过了。

参考代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline void read(int &x) 
 4 {
 5     x = 0; char c = getchar();
 6     while(!isdigit(c)) c = getchar();
 7     while(isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = getchar();
 8 }
 9 #define MAXN 1003
10 struct node{
11     int fr, to, va, nxt;
12 }edge[MAXN * MAXN * 6];
13 int head[MAXN * MAXN], cnt;
14 inline void add_edge(int u, int v, int w) {
15     edge[cnt].fr = u, edge[cnt].to = v, edge[cnt].va = w;
16     edge[cnt].nxt = head[u], head[u] = cnt++;
17     edge[cnt].fr = v, edge[cnt].to = u, edge[cnt].va = w;
18     edge[cnt].nxt = head[v], head[v] = cnt++; //反向边初始化
19 }
20 int st, ed, rank[MAXN * MAXN];
21 int BFS() {
22     queue<int> q;
23     memset(rank, 0, sizeof rank);
24     rank[st] = 1;
25     q.push(st);
26     while(!q.empty()) {
27         int tmp = q.front();
28         //cout<<tmp<<endl;
29         q.pop();
30         for(int i = head[tmp]; i != -1; i = edge[i].nxt) {
31             int o = edge[i].to;
32             if(rank[o] || edge[i].va <= 0) continue;
33             rank[o] = rank[tmp] + 1;
34             q.push(o);
35         }
36     }
37     return rank[ed];
38 }
39 int dfs(int u, int flow) {
40     if(u == ed) return flow;
41     int add = 0;
42     for(int i = head[u]; i != -1 && add < flow; i = edge[i].nxt) {
43         int v = edge[i].to;
44         if(rank[v] != rank[u] + 1 || !edge[i].va) continue;
45         int tmpadd = dfs(v, min(edge[i].va, flow - add));
46         if(!tmpadd) {  //重要!就是这里!
47             rank[v] = -1;
48             continue;
49         }
50         edge[i].va -= tmpadd, edge[i ^ 1].va += tmpadd;
51         add += tmpadd;
52     }
53     return add;
54 }
55 int ans;
56 void dinic() {
57     while(BFS()) ans += dfs(st, 0x3fffff); 
58 }
59 int n, m;
60 inline int gethash(int i, int j) {
61     return (i - 1) * m + j;
62 }
63 int main() {
64     memset(head, -1, sizeof head);
65     read(n), read(m);
66     int tmp;
67     st = 1, ed = gethash(n, m);
68     for(int i = 1; i <= n; ++i) {
69         for(int j = 1; j < m; ++j)
70             read(tmp), add_edge(gethash(i, j), gethash(i, j + 1), tmp);
71     }
72     for(int i = 1; i < n; ++i) {
73         for(int j = 1; j <= m; ++j) 
74             read(tmp), add_edge(gethash(i, j), gethash(i + 1, j), tmp);
75     }
76     for(int i = 1; i < n; ++i) {
77         for(int j = 1; j < m; ++j) 
78             read(tmp), add_edge(gethash(i, j), gethash(i + 1, j + 1), tmp);
79     }
80     dinic();
81     cout<<ans<<endl;
82     return 0;
83 } 
View Code

相关文章: