zoukankan      html  css  js  c++  java
  • 题解 UVA1349 【Optimal Bus Route Design】

    题目链接

    Solution UVA1349 Optimal Bus Route Design

    题目大意:给定一个带权有向图,选出若干个简单环,使每个点含于且仅含于一个环,并使得边权和最小

    最小费用最大流


    分析:既然每个点仅被包含于一个简单环,那么每个点的入度与出度都为(1),也就是这个点有且仅有一条入(出)边.但是我们又不能贪心的去选这个点入边/出边中边权最小的一条边,这样选出来的方案可能根本不合法(不能保证每个点都有入边,可能出现一个环加上一条链之类鬼畜的情况)

    那么我们回想一下在无权(DAG)上我们是怎么做的.每个点既要考虑它的入边,又要考虑它的出边,我们就拆点构造二分图,拆为入点和出点.用最大流来保证除去路径开头的每个点有且仅有一条入边.对于这道题同理,带权有向图上我们只需跑最小费用最大流即可

    • 最大流保证每个点都会有入边
    • 将容量设为(1)保证每个点仅有一条入边
    • 最小费用流保证边权之和最小

    我们将每个点(u)拆为两个点出点(u')和入点(u).对于每条边((u,v)),我们连边((u',v)).容量(1),费用为边权即可.然后建立超级源,往拆点后的出点(出点流向入点,所以源点要连向出点)连边,容量(1)费用(0).超级汇点同理

    然后这题就没了,一个(DAG)上最小路径覆盖的变式,挺有意思的.注意别写挂就行了

    奉上蒟蒻的代码:

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 256;
    const int maxm = (maxn * maxn + maxn + maxn) << 1;
    struct Edge{
    	int from,to,cap,flow,cost;
    	Edge() = default;
    	Edge(int a,int b,int c,int d,int e):from(a),to(b),cap(c),flow(d),cost(e){}
    }Edges[maxm];
    int head[maxn],nxt[maxm],tot = 1;
    inline void clear(){
    	tot = 1;
    	memset(head,0,sizeof(head));
    	memset(nxt,0,sizeof(nxt));
    }
    inline void addedge(int from,int to,int cap,int cost){
    	Edges[++tot] = Edge(from,to,cap,0,cost);
    	nxt[tot] = head[from];
    	head[from] = tot;
    	Edges[++tot] = Edge(to,from,0,0,-cost);
    	nxt[tot] = head[to];
    	head[to] = tot;
    }
    int a[maxn],d[maxn],inq[maxn],pre[maxn],flow,cost;
    inline bool spfa(int s,int t){
    	memset(pre,0,sizeof(pre));
    	memset(d,0x3f,sizeof(d));
    	d[s] = 0;
    	a[s] = 0x7fffffff;
    	queue<int> Q;
    	Q.push(s),inq[s] = 1;
    	while(!Q.empty()){
    		int u = Q.front();Q.pop(),inq[u] = 0;
    		for(int i = head[u];i;i = nxt[i]){
    			Edge &e = Edges[i];
    			if(e.cap > e.flow && d[e.from] + e.cost < d[e.to]){
    				d[e.to] = d[e.from] + e.cost;
    				a[e.to] = min(a[e.from],e.cap - e.flow);
    				pre[e.to] = i;
    				if(!inq[e.to])Q.push(e.to),inq[e.to] = 1;
    			}
    		}
    	}
    	if(d[t] == 0x3f3f3f3f)return false;
    	flow += a[t];
    	cost += a[t] * d[t];
    	for(int i = pre[t];i;i = pre[Edges[i].from])
    		Edges[i].flow += a[t],Edges[i ^ 1].flow -= a[t];
    	return true;
    }
    inline void mcmf(int s,int t){
    	flow = cost = 0;
    	while(spfa(s,t));
    }
    int n;
    inline void solve(){
    	clear();
    	for(int u = 1;u <= n;u++){
    		int v,d;
    		while(scanf("%d",&v) && v)
    			scanf("%d",&d),addedge(u,v + n,1,d);
    	}
    	int s = n + n + 1,t = s + 1;
    	for(int i = 1;i <= n;i++)
    		addedge(s,i,1,0);
    	for(int i = 1;i <= n;i++)
    		addedge(i + n,t,1,0);
    	mcmf(s,t);
    	if(flow != n)printf("N
    ");
    	else printf("%d
    ",cost);
    }
    int main(){
    #ifdef LOCAL
    	freopen("fafa.in","r",stdin);
    #endif
    	while(scanf("%d",&n) && n)
    		solve();
    	return 0;
    }
    
  • 相关阅读:
    (Java随机数举例)随机扔一千次硬币的正反次数
    hibernate+spring的整合思路加实例(配图解)
    从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写
    ssh连接Linux自动断开后再也无法连上的问题
    面试题10:二进制中1的个数
    C 语言统计关键字出现次数
    在Eclipse中Attach Source
    Visual Sudio 2012转换界面风格
    java 判断字符串IP合法性以及获取IP的数值形式
    java.lang.string split 以点分割字符串无法正常拆分字符串
  • 原文地址:https://www.cnblogs.com/colazcy/p/11515009.html
Copyright © 2011-2022 走看看