HLG 1542 Bombs of HRBUST(Ⅱ)(点连通度)

题意: 恐怖分子在去年轰炸哈理工未遂后,打算今年卷土重来,学校为了预防恐怖分子潜入主楼,决定在今年9月份在每间教室安装摄像头,恐怖分子为了能够成

         功潜入主楼,将要摧毁这些摄像头。

        已知摄像头的安装是成网络状的,摄像头的连接是双向的。如果网络中任何两个摄像头之间至少有一条路,则该网络为连通的,否则不连通。一个空的网络
        或只有一个摄像头的网络被认为是连通的。如果网络不连通,则导致摄像头主系统瘫痪,恐怖分子会成功潜入主楼。因为摄像头之间的连线是接在墙里的,
        所以只能靠摧毁摄像头使网络不连通,做为恐怖分子头目的你,请你计算至少要摧毁多少个摄像头才能让你的手下成功潜入主楼。
分析:使得网络不连通所需去除的最少的点的个数即为该图的点连通度,这题只要枚举起点汇点找到最小连通度即可。
        连通度总结:
        图的连通度问题是指:在图中删去部分元素(点或边),使得图中指定的两个点s和t不连通(不存在从s到t的路径),求至少要删去几个元素。
        图的连通度分为点连通度和边连通度:
      (1)点连通度:只许删点,求至少要删掉几个点(当然,s和t不能删去,这里保证原图中至少有三个点);
      (2)边连通度:只许删边,求至少要删掉几条边。
       并且,有向图和无向图的连通度求法不同,因此还要分开考虑(对于混合图,只需将其中所有的无向边按照无向图的办法处理、有向边按照有向图的办法处理即可)。
     【1】有向图的边连通度:
      这个其实就是最小割问题。以s为源点,t为汇点建立网络,原图中的每条边在网络中仍存在,容量为1,求该网络的最小割(也就是最大流)的值即为原图的边连通度。
     【2】有向图的点连通度:
      需要拆点。建立一个网络,原图中的每个点i在网络中拆成i'与i'',有一条边<i', i''>,容量为1(<s', s''>和<t', t''>例外,容量为正无穷)。原图中的每条边<i, j>在网络
      中为边<i'', j'>,容     量为正无穷。以s'为源点、t''为汇点求最大流,最大流的值即为原图的点连通度。
      最大流对应的是最小割。显然,容量为正无穷的边不可能通过最小割,也就是原图中的边和s、t两个点不能删去;若边<i, i''>通过最小割,则表示将原图中的点i删去。
     【3】无向图的边连通度:
      将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【1】)处理;
     【4】无向图的点连通度:
      将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【2】)处理。 
#include<stdio.h>
#include<string.h>
#define INF 0x1f1f1f1f
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
int gap[105];
int dis[105];
int c[105][105];
void init(int s,int u,int n)
{
    int v,x,front=0,rear=0;
    int q[105];
    clr(gap);
    memset(dis,0xff,sizeof(dis));
    q[rear++]=u;
    dis[u]=0;
    while(front<rear)
    {
        x=q[front++];
        gap[dis[x]]++;
        for(v=0;v<=n;v++)
            if(dis[v]==-1&&c[v][x]>0)
            {
                dis[v]=dis[x]+1;
                q[rear++]=v;
            }
    }
}
int sap(int s,int u,int n)
{
    init(s,u,n);
    int flag,flow=0,top=s,i,j,k;
    int pre[105];
    int low[105];
    while(dis[s]<=n)
    {
        flag=0;
        low[s]=INF;
        for(i=0;i<=n;i++)
            if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0)
            {
                flag=1;
                break;
            }
        if(flag)
        {
            low[i]=c[top][i];
            low[i]=min(low[i],low[top]);
            pre[i]=top;
            top=i;
            if(top==u)
            {
                flow+=low[u];
                j=top;
                while(j!=s)
                {
                    k=pre[j];
                    c[k][j]-=low[u];
                    c[j][k]+=low[u];
                    j=k;
                }
                top=s;
                clr(low);
            }
        }
        else
        {
            int dmin=n;
            for(j=0;j<=n;j++)
                if(c[top][j]>0&&dis[j]+1<dmin&&dis[j]>=0)
                    dmin=dis[j]+1;
            gap[dis[top]]--;
            if(gap[dis[top]]==0)
                break;
            gap[dmin]++;
            dis[top]=dmin;
            if(top!=s)
                top=pre[top];
        }
    }
    return flow;
}
struct node
{
    int from,to;
}e[100000];
int main()
{
    int n,m,i,j,res,tmp,a,b,k;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<m;i++)
        {
            scanf(" (%d,%d)",&a,&b);
            e[i].from=a;
            e[i].to=b;
        }
        res=INF;
        for(i=0;i<n;i++)
        {
            for(k=i+1;k<n;k++)
            {
                clr(c);
                for(j=0;j<n;j++)
                    c[j][j+n]=1;
                for(j=0;j<m;j++)
                {

                    c[e[j].from+n][e[j].to]=INF;
                    c[e[j].to+n][e[j].from]=INF;
                }
                tmp=sap(n+i,k,n*2-1);
                if(tmp<res)
                    res=tmp;
            }
        }
        if(res>=n)
            printf("%d\n",n);
        else printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-08-19 21:52  'wind  阅读(294)  评论(0编辑  收藏  举报