1. 程式人生 > >[BJOI2006]狼抓兔子(網絡流)

[BJOI2006]狼抓兔子(網絡流)

地形 道路 urn pri cout 第三部分 第二部分 void struct

題目描述

現在小朋友們最喜歡的"喜羊羊與灰太狼",話說灰太狼抓羊不到,但抓兔子還是比較在行的,而且現在的兔子還比較笨,它們只有兩個窩,現在你做為狼王,面對下面這樣一個網格的地形:
技術分享圖片

左上角點為(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個數,表示斜向道路的權值.

輸出格式:
輸出一個整數,表示參與伏擊的狼的最小數量.

輸入輸出樣例
輸入樣例#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
輸出樣例#1:
14

這道題算是網絡流的水題吧,看到要把兔子全部阻截掉基本上可以考慮到網絡流了。
其實這道題是要我們求最小割
由最大流=最小割(證明網上有)

直接跑最大流即可。
建邊看似麻煩實際上冷靜下來慢慢想其實很簡單了。
需要註意的是這張圖是雙向邊,我們把兩條邊的初始流量都見成\(v\)就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-'
)w=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } int n,m,cnt=1,s,t; int inf=2000000000; int head[1000001],team[1000001],deep[1000001]; struct node{ int to,next,v; }edge[6000001]; void add(int x,int y,int v) { cnt++; edge[cnt].to=y; edge[cnt].next=head[x]; edge[cnt].v=v; head[x]=cnt; } bool bfs(); int dfs(int,int); int main() { int x; n=read();m=read(); for(int i=1;i<=n;i++) { for(int j=1;j<m;j++) { x=read(); add((i-1)*m+j,(i-1)*m+j+1,x); add((i-1)*m+j+1,(i-1)*m+j,x); } } for(int i=1;i<n;i++) { for(int j=1;j<=m;j++) { x=read(); add((i-1)*m+j,i*m+j,x); add(i*m+j,(i-1)*m+j,x); } } for(int i=1;i<n;i++) { for(int j=1;j<m;j++) { x=read(); add((i-1)*m+j,i*m+j+1,x); add(i*m+j+1,(i-1)*m+j,x); } } s=1;t=n*m; int ans=0; while(bfs()) { int d; while(d=dfs(s,inf)) { ans+=d; } } printf("%d",ans); } bool bfs() { int u,v,l=0,r=1; memset(deep,0,sizeof(deep)); memset(team,0,sizeof(team)); team[1]=s;deep[s]=1; while(l<r) { l++; u=team[l]; for(int i=head[u];i;i=edge[i].next) { v=edge[i].to; if(!deep[v]&&edge[i].v>0) { r++; deep[v]=deep[u]+1; team[r]=v; } } } if(!deep[t]) return false; return true; } int dfs(int k,int v) { //cout<<k<<".."<<endl; if(k==t) return v; int u,d; for(int i=head[k];i;i=edge[i].next) { u=edge[i].to; if(deep[u]==deep[k]+1&&edge[i].v>0) { d=dfs(u,min(edge[i].v,v)); if(d>0) { edge[i].v-=d; edge[(i^1)].v+=d; return d; } } } if(d==0) deep[k]=0; return 0; }

[BJOI2006]狼抓兔子(網絡流)