标签:
题目大概说给一张有向图,要从0点出发返回0点且每条边至少都要走过一次,求走的最短路程。
经典的CPP问题,解法就是加边构造出欧拉回路,一个有向图存在欧拉回路的充分必要条件是基图连通且所有点入度等于出度。
而这题,果断联想到混合图欧拉回路的做法,用最小费用最大流解决:
另外注意判断基图连通。
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 }
HIT2739 The Chinese Postman Problem(最小费用最大流)
标签:
原文地址:http://www.cnblogs.com/WABoss/p/5398810.html