UVA 1349 Optimal Bus Route Design 最优公交路线(最小费用流)

题意:给若干景点,每个景点有若干单向边到达其他景点,要求规划一下公交路线,使得每个景点有车可达,并且每个景点只能有1车经过1次,公车必须走环形回到出发点(出发点走2次)。问是否存在这样的线路?若存在就给出所有公交车需要走过的路的长度,要求长度尽量小。

分析:这超级难发现是网络流来做的。要将每个点归结到某个环上,那么环上的点都是只有1个前驱,1个后继。如果1个前驱配1个后继,就是匹配问题了。但是这样的匹配有点混杂,所以要拆点,将1个点拆成2个,分别处于X和Y集中,然后根据有向边建图。成了带权二分图的匹配了,只是要求权最小。

  建图步骤,对于每条有向边a->b,由于b放在Y集中,编号就改变为2*b+1,而a在左边,改变为a*2,容量是1,因为只能匹配一次,费用为长度。当然肯定需要反边了!接着添加汇点,由Y集到汇点都有边,再添加源点,源点到X集都有边,他们容量都是1费用0。

  1 #include <bits/stdc++.h>
  2 #define LL long long
  3 #define pii pair<int,int>
  4 #define INF 0x7f7f7f7f
  5 using namespace std;
  6 const int N=200+50;
  7
  8 struct node
  9 {
 10     int from;
 11     int to;
 12     int val;
 13     int cap;
 14     int flow;
 15 }edge[N*N];
 16 int edge_cnt, ans_cost;
 17 int flow[N], cost[N], path[N], inq[N];
 18
 19 vector<int> vect[N];
 20
 21 void add_node(int from,int to,int val,int cap,int flow)
 22 {
 23     edge[edge_cnt].from=from;
 24     edge[edge_cnt].to=to;
 25     edge[edge_cnt].val=val;
 26     edge[edge_cnt].cap=cap;
 27     edge[edge_cnt].flow=flow;
 28     vect[from].push_back(edge_cnt++);
 29 }
 30
 31
 32 int spfa(int s,int e)
 33 {
 34     deque<int> que(1,s);
 35     inq[s]=1;
 36     flow[s]=INF;
 37     cost[s]=0;
 38     while(!que.empty())
 39     {
 40         int x=que.front();que.pop_front();
 41         inq[x]=0;
 42         for(int i=0; i<vect[x].size(); i++)
 43         {
 44             node e=edge[vect[x][i]];
 45             if( e.cap>e.flow && cost[e.to]>cost[e.from]+e.val )
 46             {
 47                 flow[e.to]=min(flow[e.from], e.cap-e.flow);
 48                 cost[e.to]=cost[e.from]+e.val;
 49                 path[e.to]=vect[x][i];
 50                 if(!inq[e.to])
 51                 {
 52                     inq[e.to]=1;
 53                     que.push_back(e.to);
 54                 }
 55             }
 56         }
 57     }
 58     return flow[e];
 59 }
 60
 61
 62 int cal(int s,int e)
 63 {
 64     int ans_flow=0;
 65     while(true)
 66     {
 67         memset(flow,0,sizeof(flow));
 68         memset(path,0,sizeof(path));
 69         memset(cost,0x7f,sizeof(cost));
 70         memset(inq,0,sizeof(inq));
 71
 72         int tmp=spfa(s,e);
 73         if(!tmp)    return ans_flow;
 74         ans_flow+=tmp;
 75         ans_cost+=cost[e];//长度
 76
 77         int ed=e;
 78         while(ed!=s)
 79         {
 80             int t=path[ed];
 81             edge[t].flow+=flow[e];
 82             edge[t^1].flow-=flow[e];
 83             ed=edge[t].from;
 84         }
 85     }
 86 }
 87
 88
 89 int main()
 90 {
 91     freopen("input.txt", "r", stdin);
 92     int n, b, v;
 93     while(scanf("%d",&n), n)
 94     {
 95         ans_cost=edge_cnt=0;
 96         for(int i=N-1; i>=0; i--)   vect[i].clear();
 97         memset(edge,0,sizeof(edge));
 98
 99         for(int i=1; i<=n; i++)
100         {
101             while(scanf("%d",&b),b)
102             {
103                 scanf("%d",&v);
104                 add_node( i*2, b*2+1, v, 1, 0 );    //编号从2~n*2+1。
105                 add_node( b*2+1, i*2, -v, 0, 0 );
106             }
107         }
108         //添加汇点n*2+2,源点0
109         for(int i=1; i<=n; i++)
110         {
111             add_node(0, i*2, 0, 1, 0);
112             add_node(i*2, 0, 0, 0, 0);
113         }
114
115         for(int i=1; i<=n; i++)
116         {
117             add_node(i*2+1, n*2+2, 0, 1, 0);
118             add_node(n*2+2, i*2+1, 0, 0, 0);
119         }
120
121         if(cal(0, n*2+2)!=n)    puts("N");
122         else    printf("%d\n",ans_cost);
123
124     }
125     return 0;
126 }

AC代码

时间: 2024-10-12 22:58:46

UVA 1349 Optimal Bus Route Design 最优公交路线(最小费用流)的相关文章

UVA 1349 - Optimal Bus Route Design(KM完美匹配)

UVA 1349 - Optimal Bus Route Design 题目链接 题意:给定一些有向带权边,求出把这些边构造成一个个环,总权值最小 思路:由于环入度出度为1,所以可以把每个点拆成入度点和出度点,然后建图做一次二分图完美匹配即可,注意这题坑点,有重边 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std

UVa 1349 Optimal Bus Route Design (最佳完美匹配)

题意:给定一个有向图,让你找出若干个图,使得每个点恰好属于一个圈,并且总的权和最小. 析:每个点都有唯一的一个圈,也就是说每一点都有唯一的后继,那么我们就可以转换成求一个图的最小权的最佳完全匹配,可以用最小费用流来求, 先把每个结点拆成两个点,假设是x,y,然后建立一个源点,向每个点的x连一条容量为1的边,建立一个汇点,每个点的y向汇点连一条容量为1的边, 每条边u,v,也连接一条容量为1,费用为权值的边,最小求一个最小费用流即可. 代码如下: #pragma comment(linker, "

UVA 1349 Optimal Bus Route Design

恰好属于一个圈,那等价与每个点有唯一的前驱和后继,那么把一个点拆开,前驱作为S集和后继作为T集,然后连边,跑二分图最小权完美匹配. 二分图最大匹配的匈牙利算法还能看懂,可是最大权完美匹配KM算法又是个什么鬼啊...只会写费用流.. #include<bits/stdc++.h> using namespace std; const int maxn = 200+6; struct Edge { int v,cap,cost,nxt; }; vector<Edge> edges; #

LA 3353 Optimal Bus Route Design 二分匹配和有向图中的环

题意:题目给出一个有向图 , 找若干个圈,使得每个结点切好属于一个圈,并且所有圈的总长度最小 , 如果没有满足条件的就输出 'N' . 注意:1.有重边 2.如果有向边(u , v) , (v , u)都存在 , 它们的长度不一定相同. 解法: 刚看这个题目的时候,没有什么思路,知道是用二分匹配之后就更没思路了.这题的关键还是在于构图: 每个点分成入度点和出度点两个点,然后在从新建图,例如:u 分成 u1 , u2 , v 分成 v1 , v2 , 假如有 (u , v) 这条边 , 那么就变成

UVA1349 Optimal Bus Route Design 拆点法+最小费用最佳匹配

/** 题目:UVA1349 Optimal Bus Route Design 链接:https://vjudge.net/problem/UVA-1349 题意:lrj入门经典P375 给n个点(n<=100)的有向带权图,找若干个有向圈,每个点恰好属于一个圈.要求权和尽量小.注意即使(u,v) 和(v,y)都存在,他们的权值也不一定相同. 思路:拆点法+最小费用最佳完美匹配. 如果每个点都有一个唯一的后继(不同的点没有相同的后继点,且只有一个后继),那么每个点一定恰好属于一个圈. 联想到二分

题解 UVA1349 【Optimal Bus Route Design】

题目链接 Solution UVA1349 Optimal Bus Route Design 题目大意:给定一个带权有向图,选出若干个简单环,使每个点含于且仅含于一个环,并使得边权和最小 分析:既然每个点仅被包含于一个简单环,那么每个点的入度与出度都为\(1\),也就是这个点有且仅有一条入(出)边.但是我们又不能贪心的去选这个点入边/出边中边权最小的一条边,这样选出来的方案可能根本不合法(不能保证每个点都有入边,可能出现一个环加上一条链之类鬼畜的情况) 那么我们回想一下在无权\(DAG\)上我们

UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design

题意: 给出一个有向带权图,找到若干个圈,使得每个点恰好属于一个圈.而且这些圈所有边的权值之和最小. 分析: 每个点恰好属于一个有向圈 就等价于 每个点都有唯一后继. 所以把每个点i拆成两个点,Xi 和 Yi ,然后求二分图最小权完美匹配(流量为n也就是满载时,就是完美匹配). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 200 + 10; 6 const int INF = 10000000

uvalive 3353 Optimal Bus Route Design

题意: 给出n个点,以及每个点到其他点的有向距离,要求设计线路使得每一个点都在一个环中,如果设计的线路拥有最小值,那么这个线路就是可选的.输出这个最小值或者说明最小线路不存在. 思路: 在DAG的最小路径覆盖中,找到的最大匹配数实际是非终点的点的最大数量(每一个匹配对应一个起点),点数减去这个数量就是终点的最少数量,一个终点对应一条路径,所以这个路径覆盖是最小的. 这个题要求每一个点都在一个环中,也就是说找到一个设计线路的方案使之不存在DAG,那么自然就没有终点存在,也就意味着每一个点都可以作为

uva1349Optimal Bus Route Design

二分图最小权完美匹配. 一个最小费用流就能跑了,记住检查一下,容量是否跑满,如果没有跑满,就说明没有完美匹配. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 500+10; const int maxm = 50000 + 10; const int inf = 0x3f3f3f3f; int g[maxn],v[maxm],f[m