HIT 2739 - The Chinese Postman Problem - [带权有向图上的中国邮路问题][最小费用最大流]
题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2739
Time limit : 1 sec Memory limit : 64 M
A Chinese postman is assigned to a small town in China to deliver letters. In this town, each street is oriented and connects exactly two junctions. The postman's task is to start at the post office and pass each street at least once to deliver letters. At last, he must return to the post office.
Can you help him to make sure whether there exist feasible routes for him and find the minimum distance from all the feasible routes.
Input
Input contains multiple test cases. The first line is an integer T, the number of test cases. Each case begins with two integers N, M, with 2 ≤ N ≤ 100, 1 ≤ M ≤ 2000, representing the number of junctions and the number of streets respectively.
Then M lines will follow, each denoting a street. A street is represented by three integers u, v, d, with 0 ≤ u, v < N, 0 < d ≤ 1000, meaning this street whose length is d connects the junction u and v and the postman can only travel from junction u to v. Junctions are numbered from 0 to N-1. Junction 0 is always the post office. Note that there may be more than one street connecting the same pair of junctions.
Output
Output one line for each test case. If there exist feasible routes for the postman, output the minimum distance. Otherwise, output -1.
Sample Input
3 2 1 0 1 3 4 4 0 1 1 1 2 2 2 3 3 3 0 4 4 7 0 1 1 1 2 2 2 3 3 3 0 4 1 3 5 3 1 2 1 3 2
Sample Output
-1 10 21
题意:
带权有向图上的中国邮路问题:
一名邮递员需要经过每条有向边至少一次,最后回到出发点;
一条边多次经过权值要累加,问最小总权值是多少。(2 <= N <= 100, 1 <= M <= 2000)
构图:
首先是比较理论的部分:
因而有:
(优先判断:若原图的基图不连通,或者存在某个点的入度或出度为 0 则无解,then可以直接跳到下一个test case;)
统计所有点的 D[i] = outdegree[i] - indegree[i];
对于 D[i] < 0 的点,加边(s, i, Di, 0);对于 D[i] > 0 的点,加边(i, t, -Di, 0);
(判断:若所有D[i]全为0,直接输出sum = Σ( all D[i][j] ) ,其中 D[i][j] 为边(i, j)的权值,then可以直接跳到下一个test case;)
对原图中的每条边(i, j),在网络中加边(i, j, ∞, D[i][j]);
求一次最小费用最大流,费用加上原图所有边权和即为结果。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #define MAXN 105 6 #define MAXM 2*(2005+2*MAXN) 7 #define INF 0x3f3f3f3f 8 using namespace std; 9 int n,m; 10 struct Edge{ 11 int u,v,c,f,a; 12 }; 13 struct MCMF 14 { 15 int s,t,ne; 16 Edge E[MAXM]; 17 int head[MAXN],next[MAXM]; 18 int vis[MAXN]; 19 int d[MAXN]; 20 int pre[MAXN]; 21 int aug[MAXN]; 22 void init() 23 { 24 ne=0; 25 memset(head,-1,sizeof(head)); 26 } 27 void addedge(int from,int to,int cap,int cost) 28 { 29 E[ne].u=from, E[ne].v=to, E[ne].c=cap, E[ne].f=0, E[ne].a=cost; 30 next[ne]=head[from]; head[from]=ne++; 31 E[ne].u=to, E[ne].v=from, E[ne].c=0, E[ne].f=0, E[ne].a=-cost; 32 next[ne]=head[to]; head[to]=ne++; 33 } 34 bool SPFA(int s,int t,int &flow,int &cost) 35 { 36 memset(d,INF,sizeof(d)); 37 memset(vis,0,sizeof(vis)); 38 d[s]=0, vis[s]=1, pre[s]=0, aug[s]=INF; 39 queue<int> q; 40 q.push(s); 41 while(!q.empty()) 42 { 43 int now=q.front(); q.pop(); 44 vis[now]=0; 45 for(int i=head[now];i!=-1;i=next[i]) 46 { 47 Edge& e=E[i]; 48 int nex=e.v; 49 if(e.c>e.f && d[nex]>d[now]+e.a) 50 { 51 d[nex]=d[now]+e.a; 52 pre[nex]=i; 53 aug[nex]=min(aug[now],e.c-e.f); 54 if(!vis[nex]) 55 { 56 q.push(nex); 57 vis[nex]=1; 58 } 59 } 60 } 61 } 62 if(d[t]==INF) return 0; 63 flow+=aug[t]; 64 cost+=d[t]*aug[t]; 65 for(int i=t;i!=s;i=E[pre[i]].u) 66 { 67 E[pre[i]].f+=aug[t]; 68 E[pre[i]^1].f-=aug[t]; 69 } 70 return 1; 71 } 72 int mincost() 73 { 74 int flow=0,cost=0,cnt=0; 75 while(SPFA(s,t,flow,cost)); 76 return cost; 77 } 78 }mcmf; 79 80 int outd[MAXN],ind[MAXN],sum; 81 int main() 82 { 83 int t; 84 scanf("%d",&t); 85 while(t--) 86 { 87 scanf("%d%d\n",&n,&m); 88 89 memset(outd,0,sizeof(outd)); 90 memset(ind,0,sizeof(ind)); 91 mcmf.s=0, mcmf.t=n+1; mcmf.init(); 92 sum=0; 93 94 for(int i=1,u,v,d;i<=m;i++) 95 { 96 scanf("%d%d%d",&u,&v,&d); 97 u++, v++, sum+=d; 98 mcmf.addedge(u,v,INF,d); 99 outd[u]++; 100 ind[v]++; 101 } 102 103 bool hasAns=1,all_d_is_zero=1; 104 for(int i=1,d;i<=n;i++) 105 { 106 if(outd[i]==0 || ind[i]==0)//显然不能有欧拉回路 107 { 108 hasAns=0; 109 break; 110 } 111 d=outd[i]-ind[i]; 112 if(d!=0) all_d_is_zero=0; 113 if(d>0) mcmf.addedge(i,mcmf.t,d,0); 114 if(d<0) mcmf.addedge(mcmf.s,i,-d,0); 115 } 116 if(!hasAns) 117 { 118 printf("-1\n"); 119 continue; 120 } 121 if(all_d_is_zero) 122 { 123 printf("%d\n",sum); 124 continue; 125 } 126 127 printf("%d\n",mcmf.mincost()+sum); 128 } 129 }
(之前2713用STL超时,搞得这题也不敢用STL,继续数组模拟邻接表,然后最大边数MAXM没开好,RE两次、TLE一次……)