[洛谷P4001][BJOI2006]狼抓兔子
题目大意:给你一个n*m的网格图,有三种边,横的,纵的和斜的,要你求出它的最小割
题解:网络流
卡点:1.无向图,反向弧容量应和正向弧相同
C++ Code:
#include<cstdio> #include<cstring> #include<cctype> #define maxn 1010*1010 using namespace std; const int inf=0x3f3f3f3f; int n,m,a,u,v; int d[maxn]; int q[maxn],h,t; int start=1,end; int head[maxn],cnt=2; struct Edge{ int to,nxt,cost; }e[maxn*6]; char ch; void read(int &x){ ch=getchar(); while (!isdigit(ch))ch=getchar(); for (x=ch^48,ch=getchar();isdigit(ch);ch=getchar())x=x*10+(ch^48); } inline int min(int a,int b){return a<b?a:b;} void add(int a,int b,int c){ e[cnt]=(Edge){b,head[a],c};head[a]=cnt; e[cnt^1]=(Edge){a,head[b],c};head[b]=cnt^1; cnt+=2; } bool bfs(){ memset(d,0,sizeof d); d[q[h=t=1]=start]=1; while (h<=t){ int x=q[h++]; if (x==end)return true; for (int i=head[x];i;i=e[i].nxt){ int to=e[i].to; if ((!d[to])&&e[i].cost){ d[to]=d[x]+1; q[++t]=to; } } } return d[end]; } int dfs(int x,int low){ if (x==end||!low)return low; int res=0,w; for (int i=head[x];i;i=e[i].nxt){ int to=e[i].to; if ((d[to]==d[x]+1)&&e[i].cost){ w=dfs(to,min(low-res,e[i].cost)); e[i].cost-=w; e[i^1].cost+=w; res+=w; if (res==low)return res; } } if (!res)d[x]=-1; return res; } void dinic(){ int ans=0,k; while (bfs()){ k=dfs(start,inf); if (k>0)ans+=k; } printf("%d\n",ans); } int main(){ read(n),read(m); for (int i=1;i<=n;i++){ for (int j=1;j<m;j++){ read(a); u=(i-1)*m+j,v=u+1; add(u,v,a); } } for (int i=1;i<n;i++){ for (int j=1;j<=m;j++){ read(a); u=(i-1)*m+j,v=u+m; add(u,v,a); } } for (int i=1;i<n;i++){ for (int j=1;j<m;j++){ read(a); u=(i-1)*m+j,v=u+m+1; add(u,v,a); } } end=n*m; dinic(); return 0; }