辣鸡卡费用流题
题目大意:给你一张有障碍网格图,n个棋子和n个洞,每次可以移动一枚棋子到(x±a,y±b),(x±b,y±a)的八个位置,不能移出边界或移动到障碍。问最少几步能使得每个洞恰好有一个棋子。任意时刻同一位置最多一个棋子。
r
,
c
≤
100
,
n
≤
500
r,c\le100,n\le500
r,c≤100,n≤500
题解:最后的限制没用。直接建图跑费用流即可,然后需要用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));
}