BZOJ 1001 狼抓兔子 (最大流转最短路) - xgtao -
1001: [BeiJing2006]狼抓兔子
题目的意思是用最少的狼封闭所有道路(即切断起点和终点),典型的最小割模型。转化一下,就给你一个二分图,让你求最大流。点数多达1000000,边数6000000条,用普通的网络流是没法过的。
那么把它转化为对偶图, 详见周东最大最小定理的论文,就这样建图。
WA了一发后,发现一定要注意m==1 || n==1时的特判,因为对偶图满足的是欧拉定理,而当它是一条线的时候,是不满足的。
#include <cstdio> #include <iostream> #include <queue> #include <algorithm> using namespace std; const int maxn = 2000020; const int maxm = 6000020; const int inf = 1<<30; struct node{ int d,u; bool operator < (const node &rhs)const{ return d > rhs.d; } }; struct edge{ int v,x; edge *nxt; }*cur,*head[maxn],meo[maxm]; int m,n,dis[maxn],done[maxn]; void adde(int u,int v,int x){ cur->v = v; cur->x = x; cur->nxt = head[u]; head[u] = cur++; cur->v = u; cur->x = x; cur->nxt = head[v]; head[v] = cur++; } void read(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } void Dijkstra(int s){ priority_queue <node>q; for(int i = 0;i <= m*n*2+2;++i)dis[i] = inf; dis[s] = 0; q.push((node){dis[s],s}); while(!q.empty()){ node p = q.top();q.pop(); int u = p.u; if(done[u])continue; done[u] = true; for(edge *it = head[u];it;it = it->nxt){ int v = it->v; if(dis[v] > dis[u]+it->x){ dis[v] = dis[u]+it->x; q.push((node){dis[v],v}); } } } } int address(int x,int y){ return ((x-1)*(m-1)+y)*2-1; } int main(){ cur = meo; scanf("%d%d",&n,&m); const int S = 0; const int T = 2*n*m+2; int x,ans = inf; if (n == 1 || m == 1) { if (n > m) swap(n, m); int ans = inf; for (int i = 1; i < m; ++i){ read(x); ans = min(ans,x); } printf("%d\n",ans); exit(0); } for(int i = 1;i <= n;++i){ for(int j = 1;j < m;++j){ read(x); if(i == 1){ adde(address(i,j),S,x); } else if(i == n){ adde(address(i-1,j)+1,T,x); } else{ adde(address(i-1,j)+1,address(i,j),x); } } } for(int i = 1;i < n;++i){ for(int j = 1;j <= m;++j){ read(x); if(j == 1){ adde(address(i,j)+1,T,x); } else if(j == m){ adde(address(i,j-1),S,x); } else{ adde(address(i,j-1),address(i,j)+1,x); } } } for(int i = 1;i < n;++i){ for(int j = 1;j < m;++j){ read(x); int pos = address(i,j),pos2 = address(i,j)+1; adde(address(i,j),address(i,j)+1,x); } } Dijkstra(S); printf("%d\n",dis[T]); return 0; }