[學習筆記] 楊柳 - zkw費用流 - 學習筆記
阿新 • • 發佈:2018-11-26
辣雞卡費用流題
題目大意:給你一張有障礙網格圖,n個棋子和n個洞,每次可以移動一枚棋子到(x±a,y±b),(x±b,y±a)的八個位置,不能移出邊界或移動到障礙。問最少幾步能使得每個洞恰好有一個棋子。任意時刻同一位置最多一個棋子。
題解:最後的限制沒用。直接建圖跑費用流即可,然後需要用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));
}