poj 1966(求图(有向和无向图)的--边连通度和顶点连通度---转为最小割)

题目描述:
        给你一个无向图,问你最少删掉几个点,使这个图成不连通。
解题报告:
概念
 
(1)一个具有 N 个顶点的图,在去掉任意 k-1 个顶点后 (1<=K<=N) 所得的子图仍连通,
  而去掉 K 个顶点后的图不连通则称 G 是连通的, K 称作图 G 的点连通度,记作 K(G) 试设计
(2)相应地如果至少去掉 K 条边使这个图不连通,则 K 成为图的边连通度
 
边连通度:
  为每条边赋权值为1,然后求确定一点作为源点,枚举此点外的每个点作为汇点求最大流。
  也可以用stoer_wagner算法求得无向图的最小割
点连通度:
  求一个给定的无向图的点连通度,可以转换为求边连通度,怎么转换就如下所示:
 
将点连通度转化为边连通度时怎么建图呢:(转载)http://blog.sina.com.cn/s/blog_64675f540100l6u3.html
1 .构造一个网络 N
若 G 为无向图:
    (1) 原 G 图中的每个顶点 v 变成 N 网中的两个顶点 v' 和 v" ,顶点 v' 至 v" 有一条弧(有向边)连接,弧容量为 1;
    (2) 原 G 图中的每条边  e = uv ,在 N 网中有两条弧 e’= u"v',e"=v"u' 与之对应, e' 弧容量为 ∞ ,  e" 弧容量为 ∞
    (3)A” 为源顶点, B' 为汇顶点   (枚举0~2*n-1点对)
     注意:弧是有向边
若 G 为有向图:
    (1) 原 G 图中的每个顶点变成 N 网中的两个顶点 v’ 和 v” ,顶点 v' 至 v” 有一条弧连接,弧容量为 1
    (2) 原 G 图中的每条弧  e = uv 变成一条有向轨 u'u"v'v" ,其中轨上的弧 u"v' 的容量为 ∞;
    (3)A” 为源顶点, B' 为汇顶点  (枚举0~2*n-1点对)
   
2 .指定一个源点 A" ,枚举汇点B',求 A" 到 B' 的最大流 F

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=505;
//const int maxm=300006;
const int inf=1<<30;
struct node
{
    int v,next;
    int val;
}s[maxn*maxn*2];


int level[maxn];//顶点的层次
int p[maxn];
int que[maxn*10];//BFS中用于遍历的顶点,DFS求增广中记录边
int out[10*maxn];//DFS用于几乎定点的分支
int ind;


inline void insert(int x,int y,int z)
{
    s[ind].v=y;
    s[ind].val=z;
    s[ind].next=p[x];
    p[x]=ind++;
    s[ind].v=x;
    s[ind].val=0;
    s[ind].next=p[y];
    p[y]=ind++;
}
int n,m;


void init()
{
    ind=0;
    memset(p,-1,sizeof(p));
}


int max_flow(int n,int source,int sink)
{
    int ret=0;
    int h=0,r=0;
    while(1)//DFS
    {
        int i;
        for(i=0;i<=n;++i)
         level[i]=0;
         h=0,r=0;




        level[source]=1;
        que[0]=source;
        while(h<=r)//BFS
        {
            int  t=que[h++];
            for(i=p[t];i!=-1;i=s[i].next)
            {
                if(s[i].val&&level[s[i].v]==0)
                {
                    level[s[i].v]=level[t]+1;
                    que[++r]=s[i].v;
                }
            }
        }
        //topset=r;//记录原点的集合个数


        if(level[sink]==0)break;//找不到汇点
        for(i=0;i<=n;++i)
        out[i]=p[i];


        int  q=-1;
        while(1)
        {
            if(q<0)
            {
                int  cur=out[source];
                for(;cur!=-1;cur=s[cur].next)
                {
                    if(s[cur].val&&out[s[cur].v]!=-1&&level[s[cur].v]==2)
                    {
                        break;
                    }
                }
                if(cur>=0)
                {
                    que[++q]=cur;
                    out[source]=s[cur].next;
                }
                else
                {
                    break;
                }
            }


            int  u=s[que[q]].v;


            if(u==sink)//一条增广路
            {
                int  dd=inf;
                int  index=-1;
                for(i=0;i<=q;i++)
                {
                    if(dd>s[que[i]].val)
                    {
                        dd=s[que[i]].val;
                        index=i;
                    }
                }
                ret+=dd;
                //cout<>n>>m)
  {


    for(int i=0;i<2*n+10;i++)
    {
        p[i]=-1;
        ind=0;
    }
    for(int i=0;i=inf)ans=n;
    cout<


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