1. 程式人生 > >HDU3844Tour (好題)

HDU3844Tour (好題)

inf strong else ret turn cnblogs oid ont ace

題意: 有N個點,M個單向邊,現在要你設計N條路線覆蓋所有的點,每個點都屬於且值屬於一個環。(為什麽是N條邊:和最小生成樹為什麽有N-1條邊是一樣的證明)。

解析: 每個點都有一個喜歡對象(出度)和被喜歡對象(入度),故將一個點拆成男點女點,然後用最佳匹配即可!

坑die:有重邊!MMP

(好像還可以用網絡流來解決,容我想兩天)

HDU3844
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<memory.h>
#include<algorithm>
#include
<cmath> using namespace std; const int maxn=310; const int inf=0x7ffffff; int map[maxn][maxn]; int vis1[maxn],vis2[maxn]; int ex1[maxn],ex2[maxn]; int lack[maxn]; int link[maxn]; int ans,n; int x1[maxn],x2[maxn],y[maxn],y2[maxn]; int Abs(int v){ if(v<0) v=-v; return v; } bool _bfs(int v) { vis1[v]
=true; for(int i=1;i<=n;i++){ if(!vis2[i]){ int tmp=ex1[v]+ex2[i]-map[v][i]; if(tmp==0){ vis2[i]=true; if(!link[i]||_bfs(link[i])){ link[i]=v; return true; } } else
if(tmp<lack[i]) lack[i]=tmp; } } return false; } void _KM() { int t,i,j; memset(link,0,sizeof(link)); memset(ex2,0,sizeof(ex2)); for(i=1;i<=n;i++){ ex1[i]=map[i][1]; for(j=2;j<=n;j++) if(ex1[i]<map[i][j]) ex1[i]=map[i][j]; } for(t=1;t<=n;t++){ for(i=1;i<=n;i++) lack[i]=inf; while(true){ memset(vis1,0,sizeof(vis1)); memset(vis2,0,sizeof(vis2)); if(_bfs(t)) break; int gap=inf; for(i=1;i<=n;i++) if(!vis2[i]&&lack[i]<gap) gap=lack[i]; for(i=1;i<=n;i++) if(vis1[i]) ex1[i]-=gap; for(i=1;i<=n;i++) if(vis2[i]) ex2[i]+=gap; for(i=1;i<=n;i++) if(!vis2[i])lack[i]-=gap; } } ans=0; for(i=1;i<=n;i++) ans-=map[link[i]][i]; ans=ans; printf("%d\n",ans); } int main() { int i,j,m,T,u,v,w; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++) map[i][j]=inf; for(i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); if(w<map[u][v]) map[u][v]=w;//消滅重邊 } for(i=1;i<=n;i++) for(j=1;j<=n;j++)map[i][j]=-map[i][j]; _KM(); } return 0; }

HDU3844Tour (好題)