【bzoj题解】1001 狼抓兔子

题目描述

现在小朋友们最喜欢"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
 左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路
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只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的的数量要最小。因为狼还要去找喜羊羊麻烦。
输入
第一行为N,M.表示网格的大小,N,M均小于等于1000。
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值。
第二部分共N-1行,每行M个数,表示纵向道路的权值。
第三部分共N-1行,每行M-1个数,表示斜向道路的权值。
输出
输出一个整数,表示参与伏击的狼的最小数量。
样例输入
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
样例输出
14
题解
裸的最小割,我转了转最大流跑Dinic。
记得连双向边。发现当前弧优化很优秀……
 1 #include<cstdio>
 2 #include<cstring>
 3 #define F(i,a,b) for(int i=a;i<=b;++i)
 4 #define F2(i,a,b) for(int i=a;i<b;++i)
 5 #define v(a,b) ((a-1)*m+b)
 6 int n,m,S,T;
 7 int h[1000001],nxt[6000001],to[6000001],cap[6000001],tot=1;
 8 inline void ins(int x,int y,int c){nxt[++tot]=h[x];to[tot]=y;cap[tot]=c;h[x]=tot;nxt[++tot]=h[y];to[tot]=x;cap[tot]=c;h[y]=tot;}
 9 int iter[1000001],lv[1000001],que[1000001],l,r;
10 inline int Min(int p,int q){return p<q?p:q;}
11 void init(){
12     int x;
13     scanf("%d%d",&n,&m); S=1, T=v(n,m);
14     F(i,1,n) F2(j,1,m)
15         scanf("%d",&x), ins(v(i,j),v(i,j+1),x);
16     F2(i,1,n) F(j,1,m)
17         scanf("%d",&x), ins(v(i,j),v(i+1,j),x);
18     F2(i,1,n) F2(j,1,m)
19         scanf("%d",&x), ins(v(i,j),v(i+1,j+1),x);
20 }
21 bool lvl(){
22     memset(lv,0,sizeof lv);
23     lv[S]=1; que[1]=S; l=r=1;
24     int u;
25     while(l<=r){
26         u=que[l++];
27         for(int i=h[u];i;i=nxt[i])
28             if(cap[i]&&!lv[to[i]]) lv[to[i]]=lv[u]+1, que[++r]=to[i];
29     } if(!lv[T]) return 0;
30     F(i,S,T) iter[i]=h[i];
31     return 1;
32 }
33 int flow(int u,int f){
34     if(u==T) return f;
35     int d,sum=0;
36     for(int&i=iter[u];i;i=nxt[i]){
37         if(cap[i]&&lv[to[i]]>lv[u]){
38             d=flow(to[i],Min(cap[i],f));
39             sum+=d; f-=d;
40             cap[i]-=d; cap[i^1]+=d;
41             if(!f) return sum;
42         }
43     }
44     return sum;
45 }
46 int Dinic(){
47     int sum=0;
48     while(lvl())
49         sum+=flow(S,999999999);
50     return sum;
51 }
52 int main(){
53     init();
54     printf("%d",Dinic());
55     return 0;
56 }

 

posted @ 2017-08-09 19:00  粉兔  阅读(464)  评论(0编辑  收藏  举报