[BeiJing2006 狼抓兔子] 最大流
From: http://www.lydsy.com/JudgeOnline/problem.php?id=1001
Solution:
这题用sap水过了, 更快的做法是转化成平面图来搞?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************************** Problem: 1001 User: leezy Language: C++ Result: Accepted Time:1292 ms Memory:141744 kb ****************************************************************/ #include <algorithm> #include <stdio.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <queue> #include <stack> #include <functional> using namespace std; const double dnf=10000000000.f; const int inf=0x7fffffff; const int maxn=1001*1001; struct edge{ int lnk,to; int c; }e[maxn*10]; int adj[maxn],now; int d[maxn],g[maxn],p[maxn],v[maxn],r[maxn]; queue<int> Q; void init(int n) {//初始化顶点集 for(int i=0;i<=n;++i)adj[i]=-1; now=0; } void ins(int a,int b,int c=0) {//添加有向边.back为反向边的边号 e[now].lnk=adj[a],e[now].to=b,e[now].c=c; adj[a]=now++; } void add(int a,int b,int c=0) { ins(a,b,c); ins(b,a); } void bfs(int t) { Q.push(t);d[t]=0; while(!Q.empty()){//计算广搜树 int u(Q.front());Q.pop(); ++g[d[u]]; for(int i=adj[u];i!=(-1);i=e[i].lnk){ if(e[i^1].c>0&&d[e[i].to]==inf){ d[e[i].to]=d[u]+1;Q.push(e[i].to); } } } } void relabel(int u,int m) { int dm=m;//初始化为顶点数 for(int i=adj[u];i!=(-1);i=e[i].lnk) dm=(e[i].c>0&&d[e[i].to]<dm)?(d[e[i].to]):(dm); d[u]=dm+1; } int sap(int s,int t,int m) { int ans=0,cf0=inf; for(int i=0;i<=m;++i) //初始化sap参数 d[i]=inf,g[i]=0,v[i]=adj[i], p[i]=-1,r[i]=0; bfs(t);//从汇点bfs for(int u(s);d[s]<m;){//从源点开始 if(u==t){ ans+=cf0; for(int i=t;p[i]!=(-1);i=p[i]) e[r[i]].c-=cf0,e[r[i]^1].c+=cf0; u=s,cf0=dnf; } int old(u); for(int i=v[u];i!=(-1);i=e[i].lnk){ if(d[e[i].to]+1!=d[u]) continue; if(e[i].c==0) continue; if(cf0>e[i].c)cf0=e[i].c; r[e[i].to]=i;p[e[i].to]=u;v[u]=i;u=e[i].to;break; } if(old==u){ if(0==(--g[d[u]])) break; v[u]=adj[u];r[u]=0; relabel(u,m);++g[d[u]]; if(u!=s){//交换p[u],u 重置p[u] int pu=p[u]; p[u]=-1;u=pu; } } } return ans; } int main() { //const char path[] = "D:\\Project\\AlgorithmExam\\test.txt"; //freopen(path, "r+", stdin); int n,m; while( scanf("%d%d", &n, &m) != EOF ){ init(n*m); for (int i = 0; i < n; ++i) for (int j = 0; j < m-1; ++j){ int I = i*m + j, J = I + 1, x; scanf("%d", &x); add( I, J, x ); add( J, I, x ); } for (int i = 0; i < n-1; ++i) for (int j = 0; j < m; ++j){ int I = i*m + j, J = (i+1)*m + j, x; scanf("%d", &x); add( I, J, x ); add( J, I, x ); } for (int i = 0; i < n-1; ++i) for (int j = 0; j < m-1; ++j){ int I = i*m + j, J = (i+1)*m + j + 1, x; scanf("%d", &x); add( I, J, x ); } printf("%d\n", sap(0, n*m-1, n*m)); } return 0; }