1. 程式人生 > >BZOJ1001_狼抓兔子_KEY

BZOJ1001_狼抓兔子_KEY

c++ == lang lan ref con gist php www.

題目傳送門

由題意得是最小割問題,又由最大流最小割定理可得只需要求無向圖的最大流即可。

建雙向邊,跑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; }

BZOJ1001_狼抓兔子_KEY