1. 程式人生 > >bzoj1001: [BeiJing2006]狼抓兔子(最大流)

bzoj1001: [BeiJing2006]狼抓兔子(最大流)

題目傳送門

解法:
每一隻兔子就需要一隻狼。
那麼我們只需要求出最多能通過多少隻兔子即可。
然後就派多少隻狼就行了唄。。
因為兔子從哪裡過來的我就在哪裡放狼。
所以狼的數量一定等於最多兔子通過的數量
題目並不要求求方案,所以不需知道兔子從哪過來。

所以直接建邊跑最大流就OK了。
注:因為是雙向邊所以反向邊流量等於正向邊流量。

程式碼實現:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std; struct node { int x,y,c,next,other; }a[6100000];int len,last[1100000]; //注意陣列大小。邊應該是3000000*2.我一開始開小了沒發現。 void ins(int x,int y,int c) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=c; //反向邊流量等於c
a[len].next=last[y],last[y]=len; a[k1].other=k2; a[k2].other=k1; } int list[1100000],head,tail; int st,ed,n,h[1100000]; bool bfs() { memset(h,0,sizeof(h));h[st]=1; head=1;tail=2;list[1]=st; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int
y=a[k].y; if(h[y]==0&&a[k].c>0) { h[y]=h[x]+1; list[tail++]=y; if(tail==ed+1) tail=1; } } head++; if(head==ed+1) head=1; } if(h[ed]==0) return false; return true; } int findflow(int x,int f) { if(x==ed) return f; int s=0,t; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==h[x]+1&&a[k].c>0&&s<f) { t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[a[k].other].c+=t; } } if(s==0) h[x]=0; return s; } int main() { int n,m;scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++) //橫著連邊 for(int j=1;j<m;j++) { int c;scanf("%d",&c); ins((i-1)*m+j,(i-1)*m+j+1,c); } for(int i=1;i<n;i++) //豎著連邊 for(int j=1;j<=m;j++) { int c;scanf("%d",&c); ins((i-1)*m+j,i*m+j,c); } for(int i=1;i<n;i++) //斜著連邊,自己yy吧。 for(int j=1;j<m;j++) { int c;scanf("%d",&c); ins((i-1)*m+j,i*m+j+1,c); } st=1;ed=n*m; int ans=0; while(bfs()==true) ans+=findflow(st,999999999); printf("%d\n",ans); return 0; }

網路流就要看清本質。
流的是什麼。怎麼構圖。
網路流還是很D的。