• NSOJ A fairy tale of the two(最小费用最大流、SPFA版本、ZKW版本)


    n,m<=20,给两个n×m布尔矩阵,每次操作可将第一个矩阵的2个相邻元素互换。输出最少操作次数使得两个矩阵完全一样。

    比赛的时候想过按照二分图完美匹配的类似做法构图,不过想到边太多以及卡各种题卡得没脾气,就先放放等赛后搞了。。。

    看题解发现有更好的构图,所以就算当时搞了也是TLE。。。。

    先对所有格子及其上下左右连条流量为inf,费用为1的边,表示使用这条边每次是花费1个操作。

    然后将第一个矩阵为1的点连S,流量为1,费用0,表示这个1可以用于满足第二个矩阵的某一个需要

    第二个矩阵为1的点连T,流量为1,费用0,表示满足了这个1的需求

    答案就是满流的最小费用了。。

    以前都是用SPFA版本的,第一次用ZKW版本。。。

    参考:

    ZKW: http://www.artofproblemsolving.com/blog/54262

    DMutehttp://blog.sina.com.cn/s/blog_76f6777d0101bbc8.html

    这里算是把ZKW封装模板化,备用。。。

    SPFA版本:1884ms

    ZKW版本:276ms

    ZKW使用的是选d[v]==d[u]+w(u,v)的思想

    SPFA版本:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    #define ll long long
    
    #define maxn 444
    #define maxe 55000
    #define inf 0x3f3f3f3f
    
    struct Edge{
        int u, v, nxt, cap, cost;
    }edge[maxe];
    int head[maxn];
    
    struct MinCostMaxFlow{
        queue<int> que;
        int add; // edges number
        int vn; // total vertex number
        int cost[maxn], in[maxn], pre[maxn];
        bool vis[maxn];
        void init(int sz){
            add = 0; vn = sz + 10; memset(head, -1, sizeof(head));
            while (!que.empty()) que.pop();
        }
        void insert(int u, int v, int w, int c){// u, v, capacity, cost
            edge[add].u = u; edge[add].v = v; edge[add].cap = w; edge[add].cost = c;
            edge[add].nxt = head[u]; head[u] = add++;
            edge[add].u = v; edge[add].v = u; edge[add].cap = 0; edge[add].cost = -c;
            edge[add].nxt = head[v]; head[v] = add++;
        }
        bool spfa(int s, int e){
            memset(cost, 0x3f3f3f3f, sizeof(cost));
            memset(in, 0, sizeof(in));
            memset(vis, 0, sizeof(vis));
            cost[s] = 0; pre[s] = -1;
            que.push(s); vis[s] = true; in[s]++;
            while (!que.empty()){
                int u = que.front(); que.pop();
                vis[u] = false;
                for (int i = head[u]; i != -1; i = edge[i].nxt){
                    int v = edge[i].v;
                    if (edge[i].cap > 0 && cost[v] > cost[u] + edge[i].cost){
                        cost[v] = cost[u] + edge[i].cost; pre[v] = i;
                        if (!vis[v]){
                            que.push(v); vis[v] = true; in[v]++;
                            if (in[v] > vn) return false;
                        }
                    }
                }
            }
            return cost[e] < inf;
        }
        void mincostmaxflow(int s, int e, int &mincost, int &maxflow){
            mincost = 0, maxflow = 0;
            while (spfa(s, e)){
                int flow = inf;
                for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
                    flow = min(flow, edge[i].cap);
                }
                maxflow += flow;
                for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
                    edge[i].cap -= flow;
                    edge[i ^ 1].cap += flow;
                }
                mincost += cost[e] * flow;
            }
        }
    }net;
    
    int a[22][22];
    int b[22][22];
    int dx[]={0,1,0,-1};
    int dy[]={1,0,-1,0};
    int main(){
    	int n,m;
    	while(~scanf("%d%d",&n,&m)){
    		for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",a[i]+j);
    		for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",b[i]+j);
    		net.init(n*m+2);
    		for(int i=1;i<=n;++i){
    			for(int j=1;j<=m;++j){
    				for(int k=0;k<4;++k){
    					int ii=i+dx[k], jj=j+dy[k];
    					int u=(i-1)*m+j, v=(ii-1)*m+jj;
    					if(ii&&jj&&ii<=n&&jj<=m) net.insert(u,v,inf,1);
    				}
    				if(a[i][j]) net.insert(0,(i-1)*m+j,1,0);
    				if(b[i][j]) net.insert((i-1)*m+j,n*m+1,1,0);
    			}
    		}
    		int ans1=-1,ans2=-1;
    		net.mincostmaxflow(0,n*m+1,ans1,ans2);
    		printf("%d
    ",ans1);
    	}
        return 0;
    }
    

     ZKW:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    #define maxn 410
    #define maxm 510000
    #define inf 0x3f3f3f3f
    
    struct Edge{
        int u,v,nxt,cap,cost;
    }edge[maxm];
    int head[maxn];
    
    struct ZKW_CostFlow{// 1-based
        int S,T;
        int add;// edges number
        bool vis[maxn];
        int dis[maxn], slk[maxn];
        int ans;
        void init(){ add=0; memset(head, -1, sizeof(head)); }
        void insert(int u, int v, int w, int c){// u, v, capacity, cost
            edge[add].u = u; edge[add].v = v; edge[add].cap = w; edge[add].cost = c;
            edge[add].nxt = head[u]; head[u] = add++;
            edge[add].u = v; edge[add].v = u; edge[add].cap = 0; edge[add].cost = -c;
            edge[add].nxt = head[v]; head[v] = add++;
        }
        int aug(int u,int f){
            int left=f;
            if(u==T){ans+=f*dis[S];return f;}
            vis[u]=true;
            for(int i=head[u];i!=-1;i=edge[i].nxt){
                int cap = edge[i].cap, v = edge[i].v;
                if(cap>0 && vis[v]==false){
                    int t = dis[v] + edge[i].cost - dis[u];
                    if(t==0){
                        int delt = aug(v, cap<left?cap : left);
                        if(delt>0) edge[i].cap-=delt, edge[i^1].cap+=delt, left-=delt;
                        if(left==0) return f;
                    }else slk[v] = t<slk[v]?t:slk[v];
                }
            }
            return f-left;
        }
        bool modlabel(int n){
            int delt = inf;
            for(int i=1;i<=n;++i)
                if(!vis[i]) delt=min(delt,slk[i]), slk[i]=inf;
            if(delt==inf) return true;
            for(int i=1;i<=n;++i)
                if(vis[i]) dis[i]+=delt;
            return false;
        }
        void ZKW_Flow(int src,int des,int n,int& micost,int& maflow){
            S=src, T=des;
            ans=micost=maflow=0;
            memset(dis,0,sizeof(dis));
            memset(slk,0x3f,sizeof(slk));
            do{
    			int tmp=0;
                do{
                    memset(vis,false,sizeof(vis));
                    maflow+=tmp;
                }while(tmp=aug(S,inf));
            }while(!modlabel(n));
            micost=ans;
        }
    }net;// 1-based
    
    int a[22][22];
    int b[22][22];
    int dx[]={0,1,0,-1};
    int dy[]={1,0,-1,0};
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",a[i]+j);
            for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",b[i]+j);
            net.init();
            for(int i=1;i<=n;++i){
                for(int j=1;j<=m;++j){
                    for(int k=0;k<4;++k){
                        int ii=i+dx[k], jj=j+dy[k];
                        int u=(i-1)*m+j, v=(ii-1)*m+jj;
                        if(ii&&jj&&ii<=n&&jj<=m) net.insert(u,v,inf,1);
                    }
                    if(a[i][j]) net.insert(n*m+1,(i-1)*m+j,1,0);
                    if(b[i][j]) net.insert((i-1)*m+j,n*m+2,1,0);
                }
            }
            int ans1=-1,ans2=-1;
            net.ZKW_Flow(n*m+1,n*m+2,n*m+2,ans1,ans2);
            printf("%d
    ",ans1);
        }
        return 0;
    }
    
  • 相关阅读:
    Mesos 配置项解析
    1039. Course List for Student (25)
    Cts框架解析(12)-ITargetPreparer
    通过ulimit改善linux系统性能(摘自IBM)
    HDU 1080 DP
    C语言调用Lua函数
    创建MySQL从库
    C# Func&lt;&gt;托付
    SpringMVC入门
    VNC连接Ubuntu 16.04桌面灰色的问题解决
  • 原文地址:https://www.cnblogs.com/nextbin/p/3932872.html
Copyright © 2020-2023  润新知