POJ 1966 Cable TV Network 顶点连通度的求解

 

 

用拆点把点权变为边权。然后用最大流求解每对u、v(u != v),取其中的最小值

注意:

具体操作时,有个技巧,可以将枚举从O(n^2)优化到O(n):

先固定一个点,然后枚举另一个点即可。

很显然的一个结论:max_flow(1->2->3) < max_flow(2->3)

我们要取其中的最小,可以不必去求2->3的最大流

如果以1为源点,汇点只能是剩下的几个点,枚举汇点即可。

 

本题要多次求最大流,所以每求一次要重新还原原图

代码1:

先把原图的信息保存在map数组里,每次都重新建图。

View Code
#include<stdio.h>
#include<string.h>
#define maxn 110
#define maxm maxn*maxn
#define inf 1000000000

int min(int a, int b)
{
    return a < b ? a : b;
}

struct E
{
    int v, next, c;
}edge[maxm<<1];
int head[maxn], tot;
int n, m;

void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}

void add(int s, int t, int c)
{
    edge[tot].v = t;
    edge[tot].c = c;
    edge[tot].next = head[s];
    head[s] = tot++;

    edge[tot].v = s;
    edge[tot].c = 0;
    edge[tot].next = head[t];
    head[t] = tot++;
}

int pre[maxn];
int cur[maxn];
int dis[maxn];
int gap[maxn];
int sap(int s, int t, int n)
{
    int i;
    for(i = 0; i <= n; i++)
        cur[i] = head[i], gap[i] = dis[i] = 0;
    gap[0] = n;
    int u = pre[s] = s, aug = inf, maxf = 0, v;
    while(dis[s] < n)
    {
loop:   for(i = cur[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].c && dis[u] == dis[v]+1)
            {
                aug = min(aug, edge[i].c);
                pre[v] = u;
                cur[u] = i;
                u = v;
                if(u == t)
                {
                    while(u != s)
                    {
                        u = pre[u];
                        edge[cur[u]].c -= aug;
                        edge[cur[u]^1].c += aug;
                    }
                    maxf += aug;
                    aug = inf;
                }
                goto loop;
            }
        }
        int min_d = n;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].c && dis[v] < min_d)
                min_d = dis[v], cur[u] = i;
        }
        if( !(--gap[dis[u]]) ) break;
        ++gap[dis[u] = min_d + 1];
        u = pre[u];
    }
    return maxf;
}


int map[maxn][maxn];
void build()
{
    int i, j;
    init();
    for(i = 0; i < 2*n; i++)
        for(j = 0; j < 2*n; j++)
            if(map[i][j] && i != j)
                add(i, j, map[i][j]);
}

int main()
{
    int i, j;
    int x, y;
    while( ~scanf("%d%d", &n, &m))
    {
        init();
        if(!m)
        {
            if(n == 1) printf("1\n");
            else printf("0\n");
            continue;
        }
        memset(map, 0, sizeof(map));
        for(i = 0; i < n; i++)
            map[i][i+n] = 1;
        while(m--)
        {
            scanf(" (%d,%d)", &x, &y);
            map[x+n][y] = map[y+n][x] = inf;
        }
        int ans = n;
        for(i = 1; i < n; i++)
        {
            build();
            ans = min( ans, sap(n, i, 2*n));
        }        
        printf("%d\n", ans);
    }
    return 0;
}

 代码2:

用反向边的信息还原原图,充分利用反向边的信息

View Code
#include<stdio.h>
#include<string.h>
#define maxn 104
#define maxm maxn*maxn
#define inf 1000000000

int min(int a, int b)
{
    return a < b ? a : b;
}

struct E
{
    int v, next, c;
}edge[maxm];
int head[maxn], tot;
int n, m;
int S, T;

void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}

void add(int s, int t, int c)
{
    edge[tot].v = t;
    edge[tot].c = c;
    edge[tot].next = head[s];
    head[s] = tot++;
    edge[tot].v = s;
    edge[tot].c = 0;
    edge[tot].next = head[t];
    head[t] = tot++;
}

int pre[maxn];
int cur[maxn];
int dis[maxn];
int gap[maxn];
int sap(int s, int t, int n)
{
    int i;
    for(i = 0; i <= n; i++)
        cur[i] = head[i], gap[i] = dis[i] = 0;
    gap[0] = n;
    int u = pre[s] = s, aug = inf, maxf = 0, v;
    while(dis[s] < n)
    {
loop:   for(i = cur[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].c && dis[u] == dis[v]+1)
            {
                aug = min(aug, edge[i].c);
                pre[v] = u;
                cur[u] = i;
                u = v;
                if(u == t)
                {
                    while(u != s)
                    {
                        u = pre[u];
                        edge[cur[u]].c -= aug;
                        edge[cur[u]^1].c += aug;
                    }
                    maxf += aug;
                    aug = inf;
                }
                goto loop;
            }
        }
        int min_d = n;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].c && dis[v] < min_d)
                min_d = dis[v], cur[u] = i;
        }
        if( !(--gap[dis[u]]) ) break;
        ++gap[dis[u] = min_d + 1];
        u = pre[u];
    }
    return maxf;
}

void init_flow()
{
    int i;
    for(i = 0; i < tot; i += 2)
    {
        edge[i].c += edge[i^1].c;
        edge[i^1].c = 0;
    }
}
int main()
{
    int i, j;
    int x, y;
    while( ~scanf("%d%d", &n, &m))
    {
        init();
        if(!m)
        {
            if(n == 1) printf("1\n");
            else printf("0\n");
            continue;
        }
        for(i = 0; i < n; i++)
            add(i, i+n, 1);
        while(m--)
        {
            scanf(" (%d,%d)", &x, &y);
            add(x+n, y, inf);
            add(y+n, x, inf);
        }
        int ans = inf;
        for(i = 1; i < n; i++)
        {
            ans = min(ans, sap(n, i, 2*n));
            init_flow();
        }
        if(ans >= inf) ans = n;
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2012-10-27 00:26  To be an ACMan  Views(275)  Comments(0)    收藏  举报