P2598 [ZJOI2009]狼和羊的故事(最小割)

Posted HWIM

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2598 [ZJOI2009]狼和羊的故事(最小割)相关的知识,希望对你有一定的参考价值。

P2598 [ZJOI2009]狼和羊的故事

题目描述

“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。

输入输出格式

输入格式:

 

文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。

 

输出格式:

 

文件中仅包含一个整数ans,代表篱笆的最短长度。

 

输入输出样例

输入样例#1: 复制
2 2
2 2 
1 1 
输出样例#1: 复制
2

说明

数据范围

10%的数据 n,m≤3

30%的数据 n,m≤20

100%的数据 n,m≤100

 

分析

最小割,使得狼与羊不连通。

注意建图:S向狼连INF的边,狼连羊连1的边,羊连T连INF的边。狼向空地,羊向空连1的边,空地与空地连1的边。

code

 

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define id(x,y) (x-1)*m+y
 5 
 6 using namespace std;
 7 
 8 const int INF = 1e9;
 9 const int N = 10010;
10 
11 struct Edge{
12     int to,nxt,c;
13 }e[100100];
14 int head[N],dis[N],cur[N],q[100100],mp[110][110];
15 int L,R,tot = 1,S,T;
16 int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
17 
18 inline char nc() {
19     static char buf[100000],*p1 = buf,*p2 = buf;
20     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
21 }
22 inline int read() {
23     int x = 0,f = 1;char ch = nc();
24     for (; ch<0||ch>9; ch = nc()) if (ch==-) f = -1;
25     for (; ch>=0&&ch<=9; ch = nc()) x = x * 10 + ch - 0;
26     return x * f;
27 }
28 inline void add_edge(int u,int v,int w) {
29     e[++tot].to = v,e[tot].c = w,e[tot].nxt = head[u],head[u] = tot;
30     e[++tot].to = u,e[tot].c = 0,e[tot].nxt = head[v],head[v] = tot;
31 }
32 bool bfs() {
33     for (int i=0; i<=T; ++i) {
34         cur[i] = head[i];dis[i] = -1;
35     }
36     L = 1;R = 0;
37     q[++R] = S;dis[S] = 0;
38     while (L <= R) {
39         int u = q[L++];
40         for (int i=head[u]; i; i=e[i].nxt) {
41             int v = e[i].to,c = e[i].c;
42             if (dis[v]==-1 && c>0) {
43                 dis[v] = dis[u] + 1;
44                 q[++R] = v;
45                 if (v==T) return true;
46             }
47         }
48     }
49     return false;
50 }
51 int dfs(int u,int flow) {
52     if (u==T) return flow;
53     int used = 0;
54     for (int &i=cur[u]; i; i=e[i].nxt) {
55         int v = e[i].to,c = e[i].c;
56         if (dis[v]==dis[u]+1 && c>0) {
57             int tmp = dfs(v,min(c,flow-used));
58             if (tmp > 0) {
59                 e[i].c -= tmp;e[i^1].c += tmp;
60                 used += tmp;
61                 if (used==flow) break;
62             }
63         }
64     }
65     if (used!=flow) dis[u] = -1;
66     return used;
67 }
68 inline int dinic() {
69     int ans = 0;
70     while (bfs()) ans += dfs(S,INF);
71     return ans;
72 }
73 int main() {
74     int n = read(),m = read();
75     S = 0;T = n*m+1;
76     for (int i=1; i<=n; ++i) 
77         for (int j=1; j<=m; ++j) 
78             mp[i][j] = read();
79     for (int i=1; i<=n; ++i) 
80         for (int j=1; j<=m; ++j) {
81             if (mp[i][j]==2) {add_edge(id(i,j),T,INF);continue;}
82             if (mp[i][j]==1) add_edge(S,id(i,j),INF); 
83             for (int k=0; k<4; ++k) {
84                 int x = i + dx[k],y = j + dy[k];
85                 if (x>0 && x<=n && y>0 && y<=m && mp[x][y]!=1)
86                     add_edge(id(i,j),id(x,y),1);
87             }
88         }
89     printf("%d",dinic());
90     return 0;
91 }

 

以上是关于P2598 [ZJOI2009]狼和羊的故事(最小割)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P2598 [ZJOI2009]狼和羊的故事

[ZJOI2009]狼和羊的故事

BZOJ1412[ZJOI2009]狼和羊的故事 最小割

BZOJ 1412 [ZJOI2009]狼和羊的故事(最小割)

bzoj 1412 [ZJOI2009]狼和羊的故事 最小割建图

BZOJ1412: [ZJOI2009]狼和羊的故事