最小费最大流,最小权最大匹配,拆点法(最优巴士路线设计 uva 1349)
2016-07-13 23:15
501 查看
紫书网络流上的题目,上面的题目简述与分析挺清楚。
给n各点(n<=100)的有向带权图,找若干个有向圈,每个点恰好属于一个圈。要求权和尽量小。若找到,则输出最小的权值,否则输出‘N’。注意及时(u,v)和(v,u)都存在,它们的权值也不一定相同。
每个点恰好属于一个圈,意味着每个点都有一个唯一的后继。反过来,只要每个点都有唯一的后继,每个点一定恰好属于一个圈。“每个东西恰好有唯一的……”让我们想到了二分图匹配。把每个点i拆成Xi和Yi,原图中的有向边u->v对应二分图中的边Xu->Yv,则题目转化为了这个二分图上的最小权完美匹配问题。
Xi就像每个点的尾巴,Yi就像每个点的头,Xu->Yv就是指u的尾巴可以和v的头相连,最小权完美匹配就是让每个尾巴都能且只能找到一个头,同时满足匹配的代价最小。
拆点法,用最小费最大流求最小权完美匹配。
将所有Xi连到源点,容量为1,费用为0。将所有Yi连到汇点,容量为1,费用为0。连Xu->Yv时,容量为1,费用为权值。跑一个从源点到汇点的最小费用最大流,若最大流为点的个数(此时从源点出发的弧与进入汇点的弧都满载)则存在完美匹配,且此时的花费为最小费用,否则不存在完美匹配。
附上渣代码
给n各点(n<=100)的有向带权图,找若干个有向圈,每个点恰好属于一个圈。要求权和尽量小。若找到,则输出最小的权值,否则输出‘N’。注意及时(u,v)和(v,u)都存在,它们的权值也不一定相同。
每个点恰好属于一个圈,意味着每个点都有一个唯一的后继。反过来,只要每个点都有唯一的后继,每个点一定恰好属于一个圈。“每个东西恰好有唯一的……”让我们想到了二分图匹配。把每个点i拆成Xi和Yi,原图中的有向边u->v对应二分图中的边Xu->Yv,则题目转化为了这个二分图上的最小权完美匹配问题。
Xi就像每个点的尾巴,Yi就像每个点的头,Xu->Yv就是指u的尾巴可以和v的头相连,最小权完美匹配就是让每个尾巴都能且只能找到一个头,同时满足匹配的代价最小。
拆点法,用最小费最大流求最小权完美匹配。
将所有Xi连到源点,容量为1,费用为0。将所有Yi连到汇点,容量为1,费用为0。连Xu->Yv时,容量为1,费用为权值。跑一个从源点到汇点的最小费用最大流,若最大流为点的个数(此时从源点出发的弧与进入汇点的弧都满载)则存在完美匹配,且此时的花费为最小费用,否则不存在完美匹配。
附上渣代码
#include<stdio.h> #include<vector> #include<queue> #include<algorithm> #define maxn 150 #define INF 0X3F3F3F3F #include<string.h> using namespace std; struct Edge { int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){} }; struct MCMF { int n,m; 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 AddEdge(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>Q; Q.push(s); while(!Q.empty()) { int u=Q.front();Q.pop(); inq[u]=0; for(unsigned 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]){Q.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 main() { int n; while(scanf("%d",&n)&&n) { MCMF mcmf; mcmf.init(2*n+2); for(int i=1;i<=n;i++) { //mcmf.AddEdge(i,i+n,1,0); mcmf.AddEdge(0,i,1,0); mcmf.AddEdge(i+n,mcmf.n-1,1,0); int a,b; while(scanf("%d",&a)&&a) { scanf("%d",&b); mcmf.AddEdge(i,a+n,1,b); } } long long cost=0; if(n==mcmf.MincostMaxflow(0,mcmf.n-1,cost)) printf("%I64d\n",cost); else printf("N\n"); } return 0; }
相关文章推荐
- uva1660 最大流
- uva1658 最小费用最大流
- POJ 3281 Dining(网络流,拆点法)
- 最大流,二分法,拆点法(士兵移动 uva 12264)
- 最小费最大流,拆点法(海军上将 uva 1658)
- UVA-1658 Admiral
- Android自学历程—手把手教你使用OkHttp(基础篇)
- 分支记录和性能监视
- navicat提权及星外主机注册表mssql密码位置
- navicat提权及星外主机注册表mssql密码位置
- hihocoder #1196 : 高斯消元·二
- 输入输出组织
- Codeforces 682C. Alyona and the Tree
- 一段机械的平均图像求背景的代码
- 打开大文件的方法
- 李洪强漫谈iOS开发[C语言-010] - C语言简要复习
- 设计模式之单例模式
- 提交时提示ip被记录,防注入系统的利用
- 产品助理day8
- Python 爬虫入门(二)—— IP代理使用