BZOJ1001: [BeiJing2006]狼抓兔子 [最小割 | 对偶图+spfa]
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 19528 Solved: 4818
[Submit][Status][Discuss]
Description
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路
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只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.
Input
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M
Output
输出一个整数,表示参与伏击的狼的最小数量.
Sample Input
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
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
Sample Output
14
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
就是用狼把这个图割开
或者想最多兔子量,然后一个兔子一个狼
法1:dinic
注意这是无向图
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=1e6+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,c,s,t; struct edge{ int v,ne,c,f; }e[N*6]; int cnt,h[N]; inline void ins(int u,int v,int c){//printf("ins %d %d %d\n",u,v,c); cnt++; e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt; } inline int id(int i,int j){return (i-1)*m+j;} int vis[N],d[N],q[N],head,tail; inline void lop(int &x){if(x==N)x=1;} bool bfs(){ memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); head=tail=1; q[tail++]=s;d[s]=0;vis[s]=1; while(head!=tail){ int u=q[head++];lop(head); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(!vis[v]&&e[i].c>e[i].f){ vis[v]=1;d[v]=d[u]+1; q[tail++]=v;lop(tail); if(v==t) return true; } } } return false; } int cur[N]; int dfs(int u,int a){ if(u==t||a==0) return a; int flow=0,f; for(int &i=cur[u];i;i=e[i].ne){ int v=e[i].v; if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){ flow+=f; e[i].f+=f; e[((i-1)^1)+1].f-=f; a-=f; if(a==0) break; } } return flow; } int dinic(){ int flow=0; while(bfs()){ for(int i=s;i<=t;i++) cur[i]=h[i]; flow+=dfs(s,INF);//printf("dinic %d\n",flow); } return flow; } int main(){ n=read();m=read();s=id(1,1);t=n*m; for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){c=read();ins(id(i,j),id(i,j+1),c);} for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++) {c=read();ins(id(i,j),id(i+1,j),c);} for(int i=1;i<=n-1;i++) for(int j=1;j<=m-1;j++){c=read();ins(id(i,j),id(i+1,j+1),c);} int ans=dinic(); printf("%d",ans); }
法2:对偶图+spfa
浅析最大最小定理在信息学竞赛中的应用
对于平面图,对偶图的最短路就是原图的最小割
直接想也容易理解,最短路就是把一些边割了
想的时候可以加一条s*到t*的INF的边把s*和t*面割开,但是程序不要加,否则暴增3000ms
1116ms,dinic用了1684ms
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=2e6+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,c,s,t; struct edge{ int v,ne,w; }e[N*4]; int h[N],cnt=0; inline void ins(int u,int v,int w){//printf("ins %d %d %d\n",u,v,w); cnt++; e[cnt].v=v;e[cnt].w=w;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].w=w;e[cnt].ne=h[v];h[v]=cnt; } inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;} int d[N],q[N],head,tail;bool inq[N]; int spfa(){ memset(d,127,sizeof(d)); head=tail=1; q[tail++]=s;inq[s]=1;d[s]=0; while(head!=tail){ int u=q[head++];inq[u]=0;lop(head); for(int i=h[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; if(!inq[v]){ if(d[v]<d[q[head]]) head--,lop(head),q[head]=v; else q[tail++]=v,lop(tail); inq[v]=1; } } } } return d[t]; } int main(){ n=read();m=read(); int col=2*(m-1),row=n-1; s=0;t=col*row+1;//ins(s,t,INF); for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++){ c=read(); if(i==1) ins(t,(j<<1),c); else if(i==n) ins((i-2)*col+(j<<1)-1,s,c); else ins((i-2)*col+(j<<1)-1,(i-1)*col+(j<<1),c); } for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++){ c=read(); if(j==1) ins(s,(i-1)*col+1,c); else if(j==m) ins((i-1)*col+(j<<1)-2,t,c); else ins((i-1)*col+(j<<1)-2,(i-1)*col+(j<<1)-1,c); } for(int i=1;i<=n-1;i++) for(int j=1;j<=m-1;j++){ c=read(); ins((i-1)*col+(j<<1)-1,(i-1)*col+(j<<1),c); } int ans=spfa(); printf("%d",ans); }
Copyright:http://www.cnblogs.com/candy99/