HIT2739 The Chinese Postman Problem(最小费用最大流)

题目大概说给一张有向图,要从0点出发返回0点且每条边至少都要走过一次,求走的最短路程。

经典的CPP问题,解法就是加边构造出欧拉回路,一个有向图存在欧拉回路的充分必要条件是基图连通且所有点入度等于出度。

而这题,果断联想到混合图欧拉回路的做法,用最小费用最大流解决:

  • 先只考虑所有边都只走一次,计算出各个点的出度和入度,出度不等于入度的点就需要选择几条边去改变调整它们
  • 对于出度多的就和容量网络的汇点连容量出度-入度费用0的边,入度多的源点就向其同样地连边
  • 对于原图中的所有边<u,v>由u向v连容量INF费用该边长度的边,一单位流量流过该边就会使原本入度多的u点的出度+1,原本出度多的v点的入度+1
  • 然后跑最小费用最大流,如果和源汇相关的边都满流那就有一个解了,而最后的解就是所有边的长度和+最小费用最大流的结果

另外注意判断基图连通。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 #define INF (1<<30)
  7 #define MAXN 111
  8 #define MAXM 8888
  9 struct Edge{
 10     int u,v,cap,cost,next;
 11 }edge[MAXM];
 12 int vs,vt,NV,NE,head[MAXN];
 13 void addEdge(int u,int v,int cap,int cost){
 14     edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
 15     edge[NE].next=head[u]; head[u]=NE++;
 16     edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
 17     edge[NE].next=head[v]; head[v]=NE++;
 18 }
 19 int d[MAXN],pre[MAXN];
 20 bool vis[MAXN];
 21 bool SPFA(){
 22     for(int i=0; i<NV; ++i){
 23         d[i]=INF; vis[i]=0;
 24     }
 25     d[vs]=0; vis[vs]=1;
 26     queue<int> que;
 27     que.push(vs);
 28     while(!que.empty()){
 29         int u=que.front(); que.pop();
 30         for(int i=head[u]; i!=-1; i=edge[i].next){
 31             int v=edge[i].v;
 32             if(edge[i].cap && d[v]>d[u]+edge[i].cost){
 33                 d[v]=d[u]+edge[i].cost;
 34                 pre[v]=i;
 35                 if(!vis[v]){
 36                     vis[v]=1;
 37                     que.push(v);
 38                 }
 39             }
 40         }
 41         vis[u]=0;
 42     }
 43     return d[vt]!=INF;
 44 }
 45 int MCMF(int &mxflow){
 46     int res=0;
 47     while(SPFA()){
 48         int flow=INF,cost=0;
 49         for(int u=vt; u!=vs; u=edge[pre[u]].u){
 50             flow=min(flow,edge[pre[u]].cap);
 51         }
 52         mxflow-=flow;
 53         for(int u=vt; u!=vs; u=edge[pre[u]].u){
 54             edge[pre[u]].cap-=flow;
 55             edge[pre[u]^1].cap+=flow;
 56             cost+=flow*edge[pre[u]].cost;
 57         }
 58         res+=cost;
 59     }
 60     return res;
 61 }
 62 int par[MAXN];
 63 int Find(int x){
 64     while(x!=par[x]){
 65         par[x]=par[par[x]];
 66         x=par[x];
 67     }
 68     return x;
 69 }
 70 bool Union(int a,int b){
 71     int pa=Find(a),pb=Find(b);
 72     if(pa==pb) return 0;
 73     par[pb]=pa;
 74     return 1;
 75 }
 76 int deg[MAXN];
 77 int main(){
 78     int t,n,m,a,b,c;
 79     scanf("%d",&t);
 80     while(t--){
 81         scanf("%d%d",&n,&m);
 82         vs=n; vt=vs+1; NV=vt+1; NE=0;
 83         memset(head,-1,sizeof(head));
 84         memset(deg,0,sizeof(deg));
 85         for(int i=0; i<n; ++i) par[i]=i;
 86         int res=0,tot=n,mxflow=0;
 87         for(int i=0; i<m; ++i){
 88             scanf("%d%d%d",&a,&b,&c);
 89             addEdge(a,b,INF,c);
 90             res+=c;
 91             ++deg[a]; --deg[b];
 92             if(Union(a,b)) --tot;
 93         }
 94         if(tot!=1){
 95             puts("-1");
 96             continue;
 97         }
 98         for(int i=0; i<n; ++i){
 99             if(deg[i]<0) addEdge(vs,i,-deg[i],0);
100             else addEdge(i,vt,deg[i],0),mxflow+=deg[i];
101         }
102         res+=MCMF(mxflow);
103         if(mxflow!=0) puts("-1");
104         else printf("%d\n",res);
105     }
106     return 0;
107 }
时间: 2024-10-08 06:28:00

HIT2739 The Chinese Postman Problem(最小费用最大流)的相关文章

HITOJ 2739 The Chinese Postman Problem(欧拉回路+最小费用流)

The Chinese Postman Problem My Tags   (Edit)   Source : bin3   Time limit : 1 sec   Memory limit : 64 M Submitted : 503, Accepted : 172 A Chinese postman is assigned to a small town in China to deliver letters. In this town, each street is oriented a

POJ 3686.The Windy&#39;s 最小费用最大流

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5477   Accepted: 2285 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The ma

最小费用最大流

Farm Tour http://poj.org/problem?id=2135 建图再说吧 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<map> 6 #include<stack> 7 #include<queue> 8 #include<vector> 9 #include&l

BZOJ 2324 营救皮卡丘(最小费用最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2324 题意:n+1个城市(0到n).初始时K个 人都在0城市.城市之间有距离.要求(1)遍历完n个城市(有一个人遍历了某个城市就算这个城市被遍历了):(2)遍历i城市前必须遍历完前i-1个城 市,并且在遍历前i-1个城市时不能经过大于等于i的城市.在满足(1)(2)的前提下使得K个人走的总距离最小. 思路:我们先看在实际情况下可以怎么走. (1)某个人遍历完某个城市后停在那里,以后不再

BZOJ 1449 球队收益(最小费用最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1449 题意: 思路:首先,我们假设后面的M场比赛两方都是输的,即初始时的lose[i]再加上i参加的场次.这样,后面对于i,每赢一场的收益增加值为: 之后win[i]++,lose[i]--.至此,我们得到建图的方法: (1)源点到每场比赛连流量1,费用0: (2)每场比赛向双方连流量1,费用0: (3)每个人到汇点连x条边(x为该人在M场比赛中出现的次数),流量1,费用为上面计算出的

BZOJ 1927 星际竞速(最小费用最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1927 题意:一个图,n个点.对于给出的每条边 u,v,w,表示u和v中编号小的那个到编号大的那个的时间为w.另外有n个值Ai,表示从任何一个点到达i点的时间为Ai.初始时你在n个点之外的一个 点上,我们称其为初始点B.要求从B出发,遍历n个点每个点一次,求最小时间.显然开始你只能使用Ai从B到达n个点中的某个点,因为B到n个点中没有其 他的边. 思路:因为最后停在了某个点上,那么从B出

BZOJ 1061 志愿者招募(最小费用最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1061 题意:申奥成功后,布布经过不懈努力,终于 成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人. 布布通过了解得知,一共有M 类志愿者可以招募.其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元.新官上任三把火,为了出色地完成自己的工作,布

POJ 2195:Going Home(最小费用最大流)

http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大流.最小费用最大流是保证在流量最大的情况下,使得费用最小. 建图是把S->人->家->T这些边弄上形成一个网络,边的容量是1(因为一个人只能和一个家匹配),边的费用是曼哈顿距离,反向边的费用是-cost. 算法的思想大概是通过SPFA找增广路径,并且找的时候费用是可以松弛的.当找到这样一条增

hdu 1533(最小费用最大流)

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4223    Accepted Submission(s): 2178 Problem Description On a grid map there are n little men and n houses. In each unit time, every l