hdu 3488 && hdu 3435 && 1853

三道类基本一样的题(费用流);

题意: 一个无向图(or 有向图), 没一个点都必须属于一个圈, 并且只能属于一个圈, 求满足要求的最小费用。

比如:

1 2 5
2 3 5
3 1 10
3 4 12
4 1 8
4 6 11
5 4 7
5 6 9
6 5 4
there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42

 

像这杨构成圈并且每个点只能属于一个圈的题, 可以转化成2 分图, 每个点只能属于一个圈, 那么出度和入度必定为1 , 那么把一个点拆开i, i`, i控制入读, i` 控制出度, 流量只能为1 。 那么对于原来途中有的边 可以 i - > j`, j - > i`;连起来构图, 然后建立超级远点s,超级汇点t,s - > i , i` - > t ; 然后求最小费用流。。这样就抱着了每个点只能属于一个圈, 因为入读 == 出度 == 1 ;这类也问题可以  做为判断性问题出。

因为出入度 都是1 所以也可以用 km 求最值。。

代码:

/* more than 1 circle && hdu 3488*/ #include using namespace std ; #define N 500 #define inf 1000000000 #define clr(c, o) memset(c, o, sizeof(c)) int map[N][N] ; int n, m, a, b, c ; int sx[N], sy[N], lx[N], ly[N], slack[N], match[N] ; bool dfs(int u, int n) { sx[u] = 1 ; for(int v = 1 ; v <= n; v ++) { if(sy[v]) continue ; int t = lx[u] + ly[v] - map[u][v] ; if( t == 0 ) { sy[v] = 1 ; if( match[v] == -1 || dfs(match[v], n)) { match[v] = u ; return true ; } } else if(t < slack[v]) slack[v] = t ; } return false ; } int KM(int n) { clr(ly,0), clr(match, -1); for(int i = 1 ; i <= n ; i ++) { lx[i] = -inf ; for(int j=1; j<=n; j++) { if(map[i][j] > lx[i]) lx[i] = map[i][j] ; } } for(int k = 1 ; k <= n ; k ++) { for(int i=1;i<=n;i++) slack[i] = inf ; while(1) { clr(sx, 0), clr(sy, 0) ; if(dfs(k, n)) break ; int d = inf ; for(int i=1; i<=n; i++) if(!sy[i] && d > slack[i]) d = slack[i] ; for(int i = 1 ; i <= n ; i ++) { if(sx[i]) lx[i] -= d ; if(sy[i]) ly[i] += d ; else slack[i] -= d ; } } } int ret = 0 ; for(int i = 1; i<=n; i++) { if(match[i] != -1 && map[match[i]][i] != -inf) ret += map[match[i]][i]; } return -ret ; } int main() { int ncas ; scanf("%d", &ncas) ; while(ncas--) { scanf("%d%d", &n, &m) ; for(int i = 1 ; i <= 2*n ; i ++) { for(int j=1; j <= 2*n; j ++) map[i][j] = -inf ; } while(m--) { scanf("%d%d%d",&a, &b ,&c) ; c = -c ; if(map[a][b+n] < c) map[a][b+n] = c ; } printf("%d/n", KM(2*n)) ; } return 0 ; }

 

 

 

你可能感兴趣的:(图论,c)