• 题解 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;
    }
    
  • 相关阅读:
    thinkphp 3.2 加载第三方库 第三方命名空间库
    自动加载
    linux定时删除文件脚本
    js问题 项目问题
    【模式识别与机器学习】——3.6感知器算法3.7采用感知器算法的多类模式的分类
    【模式识别与机器学习】——3.5Fisher线性判别
    【模式识别与机器学习】——3.3分段线性判别函数3.4模式空间和权空间
    【计算机算法设计与分析】——4.3带有限期的作业排序
    【模式识别与机器学习】——3.2广义线性判别函数
    【模式识别与机器学习】——3.1线性判别函数
  • 原文地址:https://www.cnblogs.com/colazcy/p/11515009.html
Copyright © 2020-2023  润新知