POJ 1966 Cable TV Network (用最大流求最小割点数量)

来源:互联网 发布:层次分析法判断矩阵 编辑:程序博客网 时间:2024/05/16 08:58

这道题,要注意,写网络流的时候,最好最好不要破坏原来的矩阵,尤其是需要多次求一个图的最大流的时候。

这道题,是求一个图的最小割点数。开始以为有专门的算法可以用呢,不过没有找到,然后想拆点求最小割,但是不知道无向图应该怎么建,如果正常拆点的话,拆出来的图还是一个有向图,SW只是解决无向图的情况,很纠结!要是哪位大牛路过知道有更好的算法的话,跪求指点!

这道题的做法就是,拆点,将每个点拆为入点和出点,入点和出点之间流量为1,其他点之间流量为INF,同时要注意的是,源点和汇点是不能被删掉的,所以,当你要决定哪一个点是源点或汇点的时候,记得把相应的出点和入点之间的流量改INF,因为能被删掉的一定是流量为1的边,也就是其他的点;还要注意的是,不要枚举相连的点,也就是在没有拆点之前,是相邻的点,因为在拆点之后,确定了源点和汇点,并更改了出点和入点之间的流量,那么最大流必然大于等于INF,而且相邻的点求割点,典型的没有意义,就像是一共两个点,两个点之间有一条边,删除最少的使得这个图不两通,根据题意,就是最少删除两个,把这种情况放到一个图里面,不也一样吗!所以枚举不相邻的点作为源点和汇点,一次求最大流,找出最小的最大流,就是答案了!

这里还要注意对特殊数据的特殊处理:

有一个点和0条边的,输出1;

有0个点和0条边的,输出0;

图本身就是不连通的,输出0;

以上这三情况,就不用算了。

最后,如果最小的最大流为INF,那么说明,这个图要想不连通,就删除所有点,输出n。

代码:(这里用SAP算法,但是经过实践,另外的那个算法(我不记得名字了,就是bfs找增广路)也能过)

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cctype>#include <queue>using namespace std;const int INF = 0x3fffffff;const int N = 110;int n, m, u, v, flag, g[N][N], f[N];char s[10], ch;int gap[N], dis[N], pre[N], cur[N];int a[N], flow[N][N];/*int Maxflow( int S, int E, int nodenum ){    queue<int> q;    int maxflow = 0;    memset(flow, 0, sizeof(flow));    while ( 1 ) {        memset(a, 0, sizeof(a));        a[S] = INF;        q.push(S);        while ( !q.empty() ) {            int u = q.front(); q.pop();            for ( int v = 0; v < nodenum; ++v )                 if ( !a[v] && g[u][v] > flow[u][v] ) {                    pre[v] = u;                    q.push(v);                    a[v] = min( a[u], g[u][v] - flow[u][v] );                }        }        if ( a[E] == 0 ) break;        for ( int u = E; u != S; u = pre[u] ) {            flow[pre[u]][u] += a[E];            flow[u][pre[u]] -= a[E];        }        maxflow += a[E];    }    return maxflow;}*/int Maxflow( int S, int E, int nodenum ){    memset( cur, 0, sizeof(cur));    memset( dis, 0, sizeof(dis));    memset( gap, 0, sizeof(gap));    memset( flow,0, sizeof(flow));    int u = pre[S] = S, aug = -1, maxflow = 0;    gap[0] = nodenum;    while ( dis[S] < nodenum ) {loop:        for ( int v = cur[u]; v < nodenum; v++ )             if ( g[u][v]-flow[u][v] && dis[u]==dis[v]+1 ){                if ( aug == -1 || aug > g[u][v]-flow[u][v] ) aug = g[u][v]-flow[u][v];                pre[v] = u;                u = cur[u] = v;                if ( v == E ) {                    maxflow += aug;                    for ( u = pre[u]; v != S; v = u, u = pre[u] ){                       flow[u][v] += aug;                       flow[v][u] -= aug;                    }                    aug = -1;                }                goto loop;            }        int mindis=nodenum - 1;        for ( int v = 0; v < nodenum; v++ )             if ( g[u][v]-flow[u][v] && mindis > dis[v] ){                cur[u] = v;                mindis = dis[v];            }        if ( (--gap[dis[u]]) == 0 ) break;        gap[dis[u] = mindis+1] ++;        u = pre[u];    }    return maxflow;}int find( int x ) {    return f[x] == x ? x : (f[x] = find(f[x]));}void init(){    memset( g, 0, sizeof(g));    for ( int i = 0; i < n; ++i ) f[i] = i;    while ( m ) {        ch = getchar();        if ( ch == ')' ) {           m--;           g[u][u+n] = g[v][v+n] = 1;           g[u+n][v] = g[v+n][u] = INF;           int a = find(u);           int b = find(v);           if ( a!=b ) f[a] = b;        }        if ( ch == '(' ) u = 0, flag = 1;        if ( ch == ',' ) v = 0, flag = 2;        if ( isdigit(ch) )            if ( flag == 1 ) u = u * 10 + ( ch - '0' );           else if ( flag == 2 ) v = v * 10 + ( ch -'0' );   }}int main(){    while ( scanf("%d%d", &n, &m) != EOF ) {       if ( m == 0 ) {           if ( n == 1 ) printf("1\n");           else printf("0\n");           continue;       }       init();       int is = 0, ans = INF;       for ( int i = 0; i < n; ++i ) if ( f[i] == i ) {           is++;           if ( is > 1 ) break;       }       if ( is > 1 ) {           printf("0\n");           continue;       }       for ( int i = 0; i < n; ++i )           for ( int j = i + 1; j < n; ++j )                if ( !g[i+n][j] ) {                   g[i][i+n] = INF;                   g[j][j+n] = INF;                   int tmp = Maxflow( i, j+n, 2*n );                   //cout << i << ' ' << j << ' ' << tmp << endl;                   if ( ans > tmp ) ans = tmp;                   g[i][i+n] = g[j][j+n] = 1;               }       if ( ans == INF ) ans = n;       printf("%d\n", ans);    }}


原创粉丝点击