UVA1349:Optimal Bus Route Design

题意:给定一个有向带权图,找若干个环,使得每个点属于且仅属于一个环,要求使得环权值之和最小

 

 

 

 

题解:发现这题中每个点属于且仅属于一个环,这时候“仅”这种恰好的含义,让我们想到了匹配问题

当每一个点有且只有一个后继之时,会满足题目的要求,于是把点i拆成i和i',每条边由x连向y',这样做一下二分图最优完美匹配即可

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define MAXN 5005
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
struct Edge{
    int from,to,cap,flow,cost;
    Edge(int u=0,int v=0,int c=0,int f=0,int w=0){
        from=u,to=v,cap=c,flow=f,cost=w;
    }
};
struct MCMF{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[MAXN];
    int d[MAXN];
    int p[MAXN];
    int b[MAXN];
    int a[MAXN];
    void init(int n,int s,int t){
        this->n=n;
        this->s=s,this->t=t;
        edges.clear();
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
    }
    void AddEdge(int x,int y,int cap,int cost){
        edges.push_back(Edge(x,y,cap,0,cost));
        edges.push_back(Edge(y,x,0,0,-cost));
        m=edges.size();
        G[x].push_back(m-2);
        G[y].push_back(m-1);
    }
    int SPFA(int &flow,ll &cost){
        memset(d,0x7f,sizeof(d));
        memset(b,0,sizeof(b));
        queue<int> q;
        p[s]=0;
        a[s]=INF;
        d[s]=0;
        q.push(s);
        b[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            b[x]=0;
            for(int i=0;i<G[x].size();i++){
                Edge& e=edges[G[x][i]];
                if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){
                    p[e.to]=G[x][i];
                    a[e.to]=min(a[x],e.cap-e.flow);
                    d[e.to]=d[x]+e.cost;
                    if(!b[e.to]){
                        b[e.to]=1;
                        q.push(e.to);
                    }
                }
            }
        }
        if(d[t]==INF){
            return 0;
        }
        flow+=a[t];
        cost+=1LL*d[t]*a[t];
        for(int i=t;i!=s;i=edges[p[i]].from){
            edges[p[i]].flow+=a[t];
            edges[p[i]^1].flow-=a[t];
        }
        return 1;
    }
    pair<int,ll> MincostMaxflow(){
        int flow=0;ll cost=0;
        while(SPFA(flow,cost));
        return make_pair(flow,cost);
    }
}D;
int n;
int main()
{
    while(1){
        scanf("%d",&n);
        if(!n)break;
        D.init(n<<1,0,n<<1|1);
        for(int i=1;i<=n;i++){
            D.AddEdge(0,i,1,0);
            D.AddEdge(n+i,n<<1|1,1,0);
        }
        for(int i=1;i<=n;i++){
            while(1){
                int x;scanf("%d",&x);
                if(!x)break;
                int d;scanf("%d",&d);
                D.AddEdge(i,x+n,1,d);
            }
        }
        pair<int,ll> ans=D.MincostMaxflow();
        if(ans.first==n){
            printf("%lld\n",ans.second);
        }
        else{
            printf("N\n");
        }
    }
    return 0;
}

 

posted @ 2017-11-17 10:47  white_hat_hacker  阅读(127)  评论(0编辑  收藏  举报