[学习笔记] 杨柳 - 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));
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84534674