首页 > 其他 > 详细

bzoj1412

时间:2016-01-02 10:20:47      阅读:315      评论:0      收藏:0      [点我收藏+]

题目:

1412: [ZJOI2009]狼和羊的故事

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2015  Solved: 1050
[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

2016.1.2
代码:
技术分享
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define INF 0xfffffff
 6 #define g(b) g[b.x][b.y]
 7 #define h(b) h[b.x][b.y]
 8 #define maxn 110
 9 #define inc(i,j,k) for(int i=j;i<=k;i++)
10 using namespace std;
11 
12 //edge
13 struct p{int x,y;}; struct e{p t;int c,n;}; e es[200000*2]; int ess,g[maxn][maxn];
14 void pe(p f,p t,int c){
15     es[++ess]=(e){t,c,g(f)}; g(f)=ess; 
16     es[++ess]=(e){f,0,g(t)}; g(t)=ess; 
17 }
18 
19 //maxflow
20 queue <p> q; int h[maxn][maxn];
21 bool bfs(p s,p t){//构建层次图 
22     while(! q.empty())q.pop(); memset(h,-1,sizeof(h)); h(s)=0; q.push(s);
23     while(! q.empty()){
24         p now=q.front(); q.pop();
25         for(int i=g(now);i!=-1;i=es[i].n)if(h(es[i].t)==-1&&es[i].c>0){
26             h(es[i].t)=h(now)+1; q.push(es[i].t);
27         }
28     }
29     return (h(t)==-1)?0:1;
30 }
31 int dfs(p x,p t,int flow){//找增广路并增广 
32     if(x.x==t.x&&x.y==t.y)return flow;
33     int used=0;
34     for(int i=g(x);i!=-1;i=es[i].n)if(es[i].c>0&&h(es[i].t)==h(x)+1){
35         int w=dfs(es[i].t,t,min(flow,es[i].c));
36         es[i].c-=w; es[i^1].c+=w; used+=w; flow-=w; if(flow==0)return used;
37     }
38     if(! used)h(x)=-1; return used;
39 }
40 int dicnic(p s,p t){int flow=0; while(bfs(s,t))flow+=dfs(s,t,INF); return flow;}
41 
42 //main
43 int n,m,graph[maxn][maxn];
44 int main(){
45     //freopen("zs.txt","r",stdin);
46     scanf("%d%d",&n,&m);
47     inc(i,1,n)inc(j,1,m)scanf("%d",&graph[i][j]);
48     memset(g,-1,sizeof(g)); ess=-1;
49     inc(i,1,n)inc(j,1,m){
50         if(graph[i][j]==2)pe((p){0,0},(p){i,j},INF);
51         if(graph[i][j]==1)pe((p){i,j},(p){n+1,m+1},INF);
52         if(i-1>0)pe((p){i,j},(p){i-1,j},1);
53         if(i+1<=n)pe((p){i,j},(p){i+1,j},1);
54         if(j-1>0)pe((p){i,j},(p){i,j-1},1);
55         if(j+1<=m)pe((p){i,j},(p){i,j+1},1);
56     }
57     printf("%d",dicnic((p){0,0},(p){n+1,m+1}));    
58     return 0;
59 }
View Code

题解:最小割问题,建一个超级源和超级汇,然后从源点向每只羊之间连边,容量为正无穷;每只狼向汇点连边,容量为正无穷,相邻格子之间连边,容量为1,再跑一次最大流就是结果。因为每一条同时经过羊和狼的路径都需要堵住,但又不能堵连向源点和汇点的边,所以堵住的边必定是将羊和狼分隔开的边。

dicnic:求解网络流的一种算法:先用bfs构建层次图,然后用dfs沿着层次增广,当dfs无法增广时再重复上述过程,知道源点和汇点不连通。速度比传统的EK法要快得多,但比ISAP慢,因为ISAP无法增广时是直接修改层次,同时还能用gap优化,但dicnic很好写,简洁易懂。CZL大爷说dicnic在计算本来就有一定层次的图(如二分图)时速度快,ISAP在计算一般图速度快,涨姿势了!

bzoj1412

原文:http://www.cnblogs.com/YuanZiming/p/5094166.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!