1412: [ZJOI2009]狼和羊的故事

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4017  Solved: 2037
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

2 2
2 2
1 1

Sample Output

2

数据范围
10%的数据 n,m≤3
30%的数据 n,m≤20
100%的数据 n,m≤100

开始以为是最大染色之类的问题,查题解发现居然是最大流最小割

栅栏问题可以转换为,存在两个集合,之间不存在通路,正好符合最小割的定义

开始建图

从源点S连向狼,容量为INF

从羊连向汇点T,容量为INF

从狼连向相邻的羊和空地,容量为1

从空地连向相邻的羊和空地,容量为1

跑一边最大流,代码意外的简洁

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6
 7 #define get(i,j) ((i-1)*m+j)
 8 const int INF=0x7f7f7f7f;
 9 const int MAXN=400000;
10 const int xx[4]={-1,1,0,0},yy[4]={0,0,-1,1};
11
12 struct Edge
13 {
14     int to,w,next;
15 }E[MAXN];
16 int node=1,head[MAXN],dis[MAXN],mp[200][200];
17 int s=0,t=10001;
18 int n,m,ans;
19
20 void insert(int u,int v,int w)
21 {
22     E[++node]=(Edge){v,w,head[u]};
23     head[u]=node;
24     E[++node]=(Edge){u,0,head[v]};
25     head[v]=node;
26 }
27
28 bool bfs()
29 {
30     memset(dis,-1,sizeof(dis));
31     queue<int> Q;
32     Q.push(s);
33     dis[s]=0;
34     while(!Q.empty())
35     {
36         int q=Q.front();Q.pop();
37         for(int i=head[q];i;i=E[i].next)
38             if(E[i].w&&dis[E[i].to]==-1)
39             {
40                 Q.push(E[i].to);
41                 dis[E[i].to]=dis[q]+1;
42             }
43     }
44     return dis[t]!=-1;
45 }
46
47 int dfs(int x,int flow)
48 {
49     if(x==t) return flow;
50     int w,used=0;
51     for(int i=head[x];i;i=E[i].next)
52         if(E[i].w&&dis[E[i].to]==dis[x]+1)
53         {
54             w=flow-used;
55             w=dfs(E[i].to,min(w,E[i].w));
56             E[i].w-=w;
57             E[i^1].w+=w;
58             used+=w;
59             if(used==flow)return flow;
60         }
61     if(!used) dis[x]=-1;
62     return used;
63 }
64
65 void dinic()
66 {
67     while(bfs()) ans+=dfs(s,INF);
68 }
69
70 int main()
71 {
72     scanf("%d%d",&n,&m);
73     for(int i=1;i<=n;i++)
74         for(int j=1;j<=m;j++)
75         {
76             scanf("%d",&mp[i][j]);
77             if(mp[i][j]==1) insert(s,get(i,j),INF);
78             else if(mp[i][j]==2) insert(get(i,j),t,INF);
79         }
80     for(int i=1;i<=n;i++)
81         for(int j=1;j<=m;j++)
82             for(int k=0;k<4;k++)
83             {
84                 int x=i+xx[k],y=j+yy[k];
85                 if(x<1||x>n||y<1||y>m) continue;
86                 if(mp[i][j]!=1||mp[x][y]!=1)
87                     insert(get(i,j),get(x,y),1);
88             }
89     dinic();
90     printf("%d",ans);
91     return 0;
92 }

原文地址:https://www.cnblogs.com/InWILL/p/9735856.html

时间: 2024-10-12 02:45:40

1412: [ZJOI2009]狼和羊的故事的相关文章

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

显然是最小割...把狼的领地连S, 羊的领地连T, 然后中间再连边, 跑最大流就OK了 -------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 10009; const int INF = 10

BZOJ 1412: [ZJOI2009]狼和羊的故事【网络流】

Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆.可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已.所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养. 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆

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

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1412 [题目大意] 给出一块地图,1表示狼的领地,2表示羊的领地,0表示其余动物的领地, 现在要求在格子的交界修篱笆使得羊狼的领地不能互通,求最短的篱笆长度 [题解] 我们将每个格子之间连流量为1的边,狼和源点连流量为INF的边, 羊和汇点连流量为INF的边,求此图的最小割,就是篱笆的最短修补. 思路其实很简单,使得图被划分为两个部分,羊狼分离,因此就是最小割. 求出最大流的值,就是

bzoj 1412: [ZJOI2009]狼和羊的故事

http://www.lydsy.com/JudgeOnline/problem.php?id=1412 超级源点连向所有的狼,超级汇点连向所有羊,流量为INF 相邻连边流量为1,最小割 #include<cstdio> #include<queue> #include<cstring> #include<algorithm> std::queue<int>que; int fs[5]={0,1,0,-1,0}; #define INF 0x7f

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

题面 题目传送门 解法 把\(S\)集看作和羊连接,\(T\)看作和狼连接 然后就转化成了基本的最小割模型了 对于0的处理,可以把它放在羊和狼两排点的中间,由\(S\rightarrow\)羊\(\rightarrow0\rightarrow\)狼\(\rightarrow T\) 然后跑dinic即可 代码 #include <bits/stdc++.h> #define inf 1 << 30 #define N 110 using namespace std; templat

bzoj1412: [ZJOI2009]狼和羊的故事

1412: [ZJOI2009]狼和羊的故事 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2614  Solved: 1335[Submit][Status][Discuss] Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱

ZJOI2009 狼和羊的故事

既然这题这么水,我就不写了…… 挖掘栅栏的本质:只能建在相邻两个,且建好后使得狼和羊之间不存在通路.而割的定义是:使S集和T集不存在通路.而题目又要求建的栅栏最少,于是就是最小割问题了. 从源点向所有狼连一条∞的边,从所有羊向汇点连一条∞的边,这样就能保证狼和羊都在不同的点集里.然后再从狼到相邻的羊和空地,空地到相邻的空地和羊连一条流量为1的边,最大流求最小割即可. 或者将所有点向四周连边..就是时间长了点 --hzwer 代码:(来自hzwer) 1 #include<iostream> 2

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

[BZOJ1412][ZJOI2009]狼和羊的故事 Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆.可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已.所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养. 通过仔细观察

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

P2598 [ZJOI2009]狼和羊的故事 题目描述 “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆.可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已.所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养. 通过仔细观察,Orez发现狼和羊都