1. 程式人生 > >[學習筆記] 楊柳 - zkw費用流 - 學習筆記

[學習筆記] 楊柳 - zkw費用流 - 學習筆記

辣雞卡費用流題
題目大意:給你一張有障礙網格圖,n個棋子和n個洞,每次可以移動一枚棋子到(x±a,y±b),(x±b,y±a)的八個位置,不能移出邊界或移動到障礙。問最少幾步能使得每個洞恰好有一個棋子。任意時刻同一位置最多一個棋子。 r , c 100 ,

n 500 r,c\le100,n\le500
題解:最後的限制沒用。直接建圖跑費用流即可,然後需要用zkw費用流。
zkw費用流實現起來就是使用spfa代替原來的bfs進行dinic的增廣,然後dfs的時候加一個"當前正在訪問"的標記即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long #define mp make_pair #define fir first #define sec second #define gc getchar() #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; typedef pair<int,int> pii; inline int inn() { int x,ch;while((ch=gc)
<'0'||ch>'9'); x=ch^'0';while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; } const int MAXR=110,MAXN=510; char str[MAXR];int ban[MAXR][MAXR],P[MAXR][MAXR]; namespace MINCOST_MAXFLOW_SPACE{ const int N=10010,M=400010,INF=INT_MAX/10; struct edges{ int from,to,pre,resf,cost; }e[M];int h[N],etop,d[N],cur[N]; deque<int> q;bool inq[N],vis[N]; inline int add_edge(int u,int v,int f,int c,int x=0) { return x=++etop,e[x].from=u,e[x].to=v,e[x].pre=h[u],h[u]=x,e[x].resf=f,e[x].cost=c,x; } inline int build_edge(int u,int v,int f,int c) { return add_edge(u,v,f,c),add_edge(v,u,0,-c); } inline int spfa(int s,int t) { memset(inq,false,sizeof(bool)*(t+1)); memset(vis,false,sizeof(bool)*(t+1)); memcpy(cur,h,sizeof(int)*(t+1)); while(!q.empty()) q.pop_front(); rep(i,1,t) d[i]=INF; d[s]=0,q.push_back(s),inq[s]=true; while(!q.empty()) { int x=q.front();q.pop_front(),inq[x]=false; for(int i=h[x],y;i;i=e[i].pre) if(e[i].resf&&d[y=e[i].to]>d[x]+e[i].cost) { d[y]=d[x]+e[i].cost; if(!inq[y]) q.push_back(y),inq[y]=1; } } return d[t]<INF; } int dfs(int x,int t,int a,int &cost) { if(x==t||!a) return a;int flow=0,f;vis[x]=1; for(int &i=cur[x];i;i=e[i].pre) { int y=e[i].to;if(vis[y]||d[y]!=d[x]+e[i].cost) continue; if((f=dfs(y,t,min(a,e[i].resf),cost))>0) { flow+=f,e[i].resf-=f,e[((i-1)^1)+1].resf+=f, cost+=f*e[i].cost,a-=f;if(!a) break; } } return vis[x]=0,flow; } inline int mincost_maxflow(int s,int t,int n) { int flow=0,cost=0;while(spfa(s,t)) flow+=dfs(s,t,INF,cost);return flow==n?cost:-1; } } using MINCOST_MAXFLOW_SPACE::mincost_maxflow; using MINCOST_MAXFLOW_SPACE::build_edge; using MINCOST_MAXFLOW_SPACE::INF; #define try_go(nx,ny) if((nx)>=1&&(nx)<=r&&(ny)>=1&&(ny)<=c&&!ban[nx][ny]) build_edge(P[i][j],P[nx][ny],n,1) int main() { int r=inn(),c=inn(),n=inn(),a=inn(),b=inn(),cnt=0,s=r*c+1,t=s+1,x,y; rep(i,1,r) { scanf("%s",str+1);rep(j,1,c) ban[i][j]=(str[j]=='*'); } rep(i,1,r) rep(j,1,c) P[i][j]=++cnt; rep(i,1,r) rep(j,1,c) { try_go(i+a,j+b);try_go(i+a,j-b); try_go(i-a,j+b);try_go(i-a,j-b); try_go(i+b,j+a);try_go(i+b,j-a); try_go(i-b,j+a);try_go(i-b,j-a); } rep(i,1,n) x=inn(),y=inn(),build_edge(s,P[x][y],1,0); rep(i,1,n) x=inn(),y=inn(),build_edge(P[x][y],t,1,0); return !printf("%d\n",mincost_maxflow(s,t,n)); }