UVALive 3353 - Optimal Bus Route Design(二分图最小权匹配)

题目链接 https://cn.vjudge.net/problem/UVALive-3353

【题意】
给你n个点(n<=100)的有向带权图,你要找到n个有向环,使得每个点恰好属于一个环,要求权值之和尽量小,注意即使边(u,v)和(v,u)都存在,它们的权值也不一定相同

【思路】
每个点属于一个有向圈,意味着每个点有唯一的后继,根据这个性质来建图,每个点拆成一个X结点和一个Y结点,原图中u->v对应二分图中x[u]->Y[v],然后就转换成了二分图的最小权匹配问题了,用最小费用最大流或者KM都可以.

#include<bits/stdc++.h>
using namespace std;

const int inf=2e9;
const int maxn=220;

struct Edge{
    int from,to,cap,flow,cost;
    Edge(int u,int v,int c,int f,int co):from(u),to(v),cap(c),flow(f),cost(co){}
};

struct MCMF{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> g[maxn];
    int inq[maxn];  
    int d[maxn];    
    int p[maxn];    
    int a[maxn];    

    void init(int n){
        this->n=n;
        for(int i=0;i<=n;++i) g[i].clear();
        edges.clear();
    }

    void add(int from,int to,int cap,int cost){
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m=edges.size();
        g[from].push_back(m-2);
        g[to].push_back(m-1);
    }

    bool BellmanFord(int s,int t,int& flow,long long& cost){
        for(int i=0;i<n;++i) d[i]=inf;
        memset(inq,0,sizeof(inq));
        d[s]=0;
        inq[s]=1;
        p[s]=0;
        a[s]=inf;

        queue<int> que;
        que.push(s);
        while(!que.empty()){
            int u=que.front();
            que.pop();
            inq[u]=0;
            for(int i=0;i<g[u].size();++i){
                Edge& e=edges[g[u][i]];
                if(e.cap>e.flow && d[e.to]>d[u]+e.cost){
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=g[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!inq[e.to]){ que.push(e.to);inq[e.to]=1; }
                }
            }
        }
        if(d[t]==inf) return false;
        flow+=a[t];
        cost+=(long long)d[t]*(long long)a[t];
        for(int u=t;u!=s;u=edges[p[u]].from){
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }

    int MincostMaxflow(int s,int t,long long& cost){
        int flow=0;
        cost=0;
        while(BellmanFord(s,t,flow,cost));
        return flow;
    }
};

int n;
MCMF mcmf;

int main(){
    while(scanf("%d",&n)==1 && n){
        mcmf.init(2*n+2);
        for(int u=1;u<=n;++u){
            mcmf.add(0,u,1,0);
            mcmf.add(u+n,2*n+1,1,0);
            int v,w;
            while(scanf("%d",&v)){
                if(0==v) break;
                scanf("%d",&w);
                mcmf.add(u,v+n,1,w);
            }
        }
        long long ans;
        int flow=mcmf.MincostMaxflow(0,2*n+1,ans);
        if(flow==n) printf("%lld\n",ans);
        else puts("N");
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef int type;

const type inf = 2e9;
const int maxn = 220;

int n, m;
int matchx[maxn], matchy[maxn];
int visx[maxn], visy[maxn];
type lx[maxn], ly[maxn];
type w[maxn][maxn];
type slack[maxn];

bool dfs(int x){
    visx[x] = 1;
    for (int y = 0; y < m; ++y) {
        if (visy[y]) continue;
        type tmp = lx[x] + ly[y] - w[x][y];
        if (tmp == 0) {
            visy[y] = 1;
            if (matchy[y] == -1 || dfs(matchy[y])) {
                matchx[x] = y;
                matchy[y] = x;
                return true;
            }
        }
        else {
            slack[y] = min(slack[y], tmp);
        }
    }
    return false;
}

void KM() {
    memset(matchy, -1, sizeof(matchy));
    memset(ly, 0, sizeof(ly));
    for (int i = 0; i < n; ++i) {
        lx[i] = -inf;
        for (int j = 0; j < m; ++j) {
            lx[i] = max(lx[i], w[i][j]);
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) slack[j] = inf;
        while (1) {
            memset(visx, 0, sizeof(visx));
            memset(visy, 0, sizeof(visy));
            if (dfs(i)) break;
            type d = inf;
            for (int j = 0; j < m; ++j) {
                if (!visy[j]) d = min(d, slack[j]);
            }
            for (int j = 0; j < n; ++j) { if (visx[j]) lx[j] -= d; }
            for (int j = 0; j < m; ++j) {
                if (visy[j]) ly[j] += d;
                else slack[j] -= d;
            }
        }
    }
}

int main() {
    while (scanf("%d", &n) == 1 && n) {
        m = n;
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j) w[i][j]=-inf;
        }
        for(int u=0;u<n;++u){
            int v,cost;
            while(scanf("%d",&v) && v){
                --v;
                scanf("%d",&cost);
                w[u][v]=-cost;
            }
        }
        KM();
        int ans = 0;
        bool ok=true;
        for (int i = 0; i < n; ++i) {
            if(w[i][matchx[i]]==-inf) {ok=false;break;}
            ans += w[i][matchx[i]];
        }
        if(ok) printf("%d\n", -ans);
        else puts("N");
    }
    return 0;
}
posted @ 2018-08-20 21:35  不想吃WA的咸鱼  阅读(113)  评论(0编辑  收藏  举报