题意:Little Tom要“环”游一些城市,每个城市只能游玩一次。现在给出一张有向图和每条边的费用。求最小费用。
要走环,很容易想到二分图匹配。这里还是一样的,拆点。把每个点拆开,变成i,i',分别和源点S汇点T相连,费用是0,容量是1。然后对原图中的每条边(u,v),对应边(u,v',1,cost),跑费用流,如果最大流=城市数,说明存在一个方案,答案就是最小费用流算出来的费用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define maxn 210 6 #define maxm 100000 7 #define INF 1<<30 8 using namespace std; 9 struct MCMF{ 10 int src,sink,e,n; 11 int first[maxn]; 12 int cap[maxm],cost[maxm],v[maxm],next[maxm]; 13 void init(){ 14 e = 0; 15 memset(first,-1,sizeof(first)); 16 } 17 void add_edge(int a,int b,int cc,int ww){ 18 v[e] = b;next[e] = first[a];cap[e] = cc; 19 cost[e] = ww;first[a] = e++; 20 v[e] = a;next[e] = first[b];cap[e] = 0; 21 cost[e] = -ww;first[b] = e++; 22 } 23 24 int d[maxn],pre[maxn],pos[maxn]; 25 bool vis[maxn]; 26 27 bool spfa(int s,int t){ 28 memset(pre,-1,sizeof(pre)); 29 memset(vis,0,sizeof(vis)); 30 queue<int> Q; 31 for(int i = 0;i <= n;i++) d[i] = INF; 32 Q.push(s);pre[s] = s;d[s] = 0;vis[s] = 1; 33 while(!Q.empty()){ 34 int u = Q.front();Q.pop(); 35 vis[u] = 0; 36 for(int i = first[u];i != -1;i = next[i]){ 37 if(cap[i] > 0 && d[u] + cost[i] < d[v[i]]){ 38 d[v[i]] = d[u] + cost[i]; 39 pre[v[i]] = u;pos[v[i]] = i; 40 if(!vis[v[i]]) vis[v[i]] = 1,Q.push(v[i]); 41 } 42 } 43 } 44 return pre[t] != -1; 45 } 46 47 int Mincost,Maxflow; 48 int MincostFlow(int s,int t,int nn){ 49 Mincost = Maxflow = 0,n = nn; 50 while(spfa(s,t)){ 51 int min_f = INF; 52 for(int i = t;i != s;i = pre[i]) 53 if(cap[pos[i]] < min_f) min_f = cap[pos[i]]; 54 Mincost += d[t] * min_f; 55 Maxflow += min_f; 56 for(int i = t;i != s;i = pre[i]){ 57 cap[pos[i]] -= min_f; 58 cap[pos[i]^1] += min_f; 59 } 60 } 61 return Mincost; 62 } 63 }; 64 MCMF g; 65 66 int main() 67 { 68 int n,m; 69 while(scanf("%d%d",&n,&m) == 2){ 70 g.init(); 71 int S = 0,T = 2*n+1; 72 for(int i = 1;i <= n;i++){ 73 g.add_edge(S,i,1,0); 74 g.add_edge(i+n,T,1,0); 75 } 76 for(int i = 1;i <= m;i++){ 77 int a,b,c; 78 scanf("%d%d%d",&a,&b,&c); 79 g.add_edge(a,b+n,1,c); 80 } 81 int ans = g.MincostFlow(S,T,T); 82 if(g.Maxflow == n) printf("%d ",ans); 83 else printf("-1 "); 84 } 85 return 0; 86 }