题意:给出一个有向图,边带权,求一些环,使得每个点属于且仅属于一个环,幷最小化环边的权值和。
思想和最小路径覆盖是一样的,将每个定点拆成两个点,假设u拆成u1,u2,那么所有边(v,u)对应新图中的(v1,u2),(u,v)对应(u1,v2)。
然后会发现一种合法方案和新图(是一个二分图)的一个完美匹配一一对应。
然后就可以用KM或网络流解决了。
(这种有向图路径拆边的思想很漂亮)
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define oo 0x3f3f3f3f 6 #define maxn 410 7 using namespace std; 8 9 struct Edge { 10 int u, v, c, f; 11 Edge( int u, int v, int c, int f ):u(u),v(v),c(c),f(f){} 12 }; 13 struct Mcmf { 14 int n, src, dst; 15 vector<Edge> edge; 16 vector<int> g[maxn]; 17 int dis[maxn], ext[maxn], pth[maxn]; 18 19 void init( int nn, int s, int d ) { 20 n = nn; 21 src = s; 22 dst = d; 23 for( int i=1; i<=n; i++ ) 24 g[i].clear(); 25 edge.clear(); 26 } 27 void add_edge( int u, int v, int c, int f ) { 28 g[u].push_back( edge.size() ); 29 edge.push_back( Edge(u,v,c,f) ); 30 g[v].push_back( edge.size() ); 31 edge.push_back( Edge(v,u,-c,0) ); 32 } 33 bool spfa( int &flow, int &cost ) { 34 queue<int> qu; 35 memset( dis, 0x3f, sizeof(dis) ); 36 qu.push( src ); 37 dis[src] = 0; 38 ext[src] = true; 39 pth[src] = -1; 40 while( !qu.empty() ) { 41 int u=qu.front(); 42 qu.pop(); 43 ext[u] = false; 44 for( int t=0; t<g[u].size(); t++ ) { 45 Edge &e = edge[g[u][t]]; 46 if( e.f && dis[e.v]>dis[e.u]+e.c ) { 47 dis[e.v] = dis[e.u]+e.c; 48 pth[e.v] = g[u][t]; 49 if( !ext[e.v] ) { 50 ext[e.v] = true; 51 qu.push( e.v ); 52 } 53 } 54 } 55 } 56 if( dis[dst]==oo ) return false; 57 int flw = oo; 58 for( int eid=pth[dst]; eid!=-1; eid=pth[edge[eid].u] ) 59 flw = min( flw, edge[eid].f ); 60 for( int eid=pth[dst]; eid!=-1; eid=pth[edge[eid].u] ) { 61 edge[eid].f -= flw; 62 edge[eid^1].f += flw; 63 } 64 flow += flw; 65 cost += flw*dis[dst]; 66 return true; 67 } 68 void mcmf( int &flow, int &cost ) { 69 flow = cost = 0; 70 while( spfa(flow,cost) ); 71 } 72 }; 73 74 int n, m; 75 Mcmf M; 76 77 int main() { 78 int T; 79 scanf( "%d", &T ); 80 while(T--) { 81 scanf( "%d%d", &n, &m ); 82 int tot = n+n+2; 83 M.init( tot, tot-1, tot ); 84 for( int i=1,u,v,w; i<=m; i++ ) { 85 scanf( "%d%d%d", &u, &v, &w ); 86 M.add_edge( u, v+n, w, 1 ); 87 } 88 for( int u=1; u<=n; u++ ) { 89 M.add_edge( M.src, u, 0, 1 ); 90 M.add_edge( u+n, M.dst, 0, 1 ); 91 } 92 int flow, cost; 93 M.mcmf(flow,cost); 94 printf( "%d\n", cost ); 95 } 96 }
时间: 2024-10-13 10:28:17