【Luogu】P3159交换棋子(超出我能力范围的费用流)

  题目链接

  明显超出我能力范围。

  只放题解

  再放代码。

#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<queue>
#define maxn 100200
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int n,m;
inline int calc(int x,int y,int z){    return (x-1)*m+y+(z-1)*(n*m);    }
inline int count(int i){    return i&1?i+1:i-1;    }
struct Edge{
    int from,next,to,dis,val,flow;
}edge[maxn];
int head[maxn],num;
inline void addedge(int from,int to,int dis,int val){
    edge[++num]=(Edge){from,head[from],to,dis,val,0};
    head[from]=num;
}
inline void add(int from,int to,int dis,int val){
    addedge(from,to,dis,val);
    addedge(to,from,-dis,0);
}

bool sta[100][100];
bool edn[100][100];
int swa[100][100];
int Start,End;

int u[9]={0,0,1,1,1,0,-1,-1,-1};
int w[9]={0,1,1,0,-1,-1,-1,0,1};

struct Ans{
    long long dis,val;
    Ans(){dis=val=0;}
};

long long dis[maxn];
long long pre[maxn];
int flow[maxn];
bool vis[maxn];
int sum;

Ans spfa(){
    Ans ans;
    memset(dis,127/3,sizeof(dis));    long long Max=dis[0];
    dis[Start]=0;    flow[Start]=0x7fffffff;
    queue<int>q;    q.push(Start);
    while(!q.empty()){
        int from=q.front();q.pop();vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(edge[i].dis+dis[from]>=dis[to]||edge[i].val==edge[i].flow)    continue;
            dis[to]=dis[from]+edge[i].dis;
            pre[to]=i;
            flow[to]=min(flow[from],edge[i].val-edge[i].flow);
            if(!vis[to]){
                vis[to]=1;
                q.push(to);
            }
        }
    }
    if(dis[End]==Max)    return ans;
    long long now=End;    ans.val=flow[End];    ans.dis=dis[End];
    sum+=flow[End];
    while(now!=Start){
        long long ret=pre[now];
        edge[ret].flow+=flow[End];
        edge[count(ret)].flow-=flow[End];
        now=edge[ret].from;
    }
    return ans;
}

int main(){
    n=read(),m=read();
    End=calc(n,m,3)+1;
    for(int i=1;i<=n;++i){
        char ch[100];
        scanf("%s",ch+1);
        for(int j=1;j<=m;++j)    sta[i][j]=ch[j]-'0';
    }
    for(int i=1;i<=n;++i){
        char ch[100];
        scanf("%s",ch+1);
        for(int j=1;j<=m;++j)    edn[i][j]=ch[j]-'0';
    }
    for(int i=1;i<=n;++i){
        char ch[100];
        scanf("%s",ch+1);
        for(int j=1;j<=m;++j)    swa[i][j]=ch[j]-'0';
    }
    int sum1=0,sum2=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            if(sta[i][j]){
                sum1++;
                add(Start,calc(i,j,2),0,1);
            }
            if(edn[i][j]){
                sum2++;
                add(calc(i,j,2),End,0,1);
            }
            if(sta[i][j]&&(!edn[i][j])){
                add(calc(i,j,1),calc(i,j,2),1,swa[i][j]>>1);
                add(calc(i,j,2),calc(i,j,3),0,(swa[i][j]+1)>>1);
            }
            if((!sta[i][j])&&edn[i][j]){
                add(calc(i,j,1),calc(i,j,2),1,(swa[i][j]+1)>>1);
                add(calc(i,j,2),calc(i,j,3),0,swa[i][j]>>1);
            }
            if(sta[i][j]==edn[i][j]){
                add(calc(i,j,1),calc(i,j,2),1,swa[i][j]>>1);
                add(calc(i,j,2),calc(i,j,3),0,swa[i][j]>>1);
            }
            for(int k=1;k<9;++k){
                int x=i+u[k];int y=j+w[k];
                if(x<1||x>n||y<1||y>m)    continue;
                add(calc(i,j,3),calc(x,y,1),0,0x7fffffff);
            }
        }
    if(sum1!=sum2){
        printf("-1");
        return 0;
    }
    int ans=0;
    while(1){
        Ans now=spfa();
        if(!now.val)    break;
        ans+=now.val*now.dis;
    }
    if(sum!=sum1){
        printf("-1");
        return 0;
    }
    printf("%d",ans);
    return 0;
}

https://www.luogu.org/problemnew/solution/P3159

原文地址:https://www.cnblogs.com/cellular-automaton/p/8260920.html