BZOJ1001_狼抓兔子_KEY
由题意得是最小割问题,又由最大流最小割定理可得只需要求无向图的最大流即可。
建双向边,跑Dinic,EK会超时。
注意在DFS时要加"if(!res)dist[now]=0;"这句话,不然会超时。
这句话因为下次DFSnow这个点时得到的最小流量为0,所以就没必要DFS下去,一个剪枝。
code:
/************************************************************** Problem: 1001 User: yekehe Language: C++ Result: Accepted Time:1916 ms Memory:102480 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; char tc() { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } int read() { char c;while(c=tc(),(c<'0'||c>'9')&&c!='-'); int x=0,y=1;c=='-'?y=-1:x=c-'0'; while(c=tc(),c>='0'&&c<='9')x=x*10+c-'0'; return x*y; } const int MAXN=1000005,MAXM=6000005; int N,M,ans; struct edge{ int to,v; }L[MAXM]; int head[MAXN],nxt[MAXM],cnt; int l[MAXM],h,t,S,T,dist[MAXN]; void add(int x,int y,int fx,int fy,int c) { int u=(x-1)*M+y,v=(fx-1)*M+fy; L[cnt]=(edge){v,c}; nxt[cnt]=head[u]; head[u]=cnt; cnt++; } bool BFS() { h=t=0; l[++t]=S; memset(dist,0,sizeof(dist)); dist[S]=1; while(h<t){ int front=l[++h]; for(int i=head[front];i!=-1;i=nxt[i]){ int to=L[i].to; if(!dist[to] && L[i].v){ dist[to]=dist[front]+1; l[++t]=to; } } } return dist[T]; } int DFS(int now,int x) { if(now==T)return x; int res=0; for(int i=head[now];i!=-1 && x;i=nxt[i]){ int to=L[i].to; if(dist[to]==dist[now]+1 && L[i].v){ int fd=DFS(to,min(x,L[i].v)); x-=fd;L[i].v-=fd; res+=fd;L[i^1].v+=fd; } } if(!res)dist[now]=0; return res; } int main() { // freopen("x.txt","r",stdin); N=read(),M=read(); memset(head,-1,sizeof(head)); register int i,j; int c; for(i=1;i<=N;i++)for(j=1;j<M;j++)c=read(),add(i,j,i,j+1,c),add(i,j+1,i,j,c); for(i=1;i<N;i++)for(j=1;j<=M;j++)c=read(),add(i,j,i+1,j,c),add(i+1,j,i,j,c); for(i=1;i<N;i++)for(j=1;j<M;j++)c=read(),add(i,j,i+1,j+1,c),add(i+1,j+1,i,j,c); S=1,T=N*M; while(BFS()){ ans+=DFS(S,2e9); } printf("%d",ans); return 0; }