poj 1966 无向图的点连通度

/********************************************************************
 ** @brief   图的连通度问题是指:在图中删去部分元素(点或边),使得图中指定的两个点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<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 105
#define INF 105
int map[MAX][MAX];
int N,M;
#define MAXN 105   
//#define INF 105   
#define MIN(x,y) (x<y?x:y) 
int n,m;
int max_flow(int num,int s,int t){//参考算法导论的 Edmonds-Karp 算法。
  int f[MAX],//记录结点的父节点
    min_flow[MAX];//当前路径中最小的一段的值,也即限制值  
  int flow[MAX][MAX];//记录当前网络中的流
  queue<int>q;
  int ans=0;
  memset(flow,0,sizeof(flow));
  while(true){//一直循环,直到不存在增广路径   
    while(!q.empty())q.pop();
    memset(f,-1,sizeof(f));
    f[s]=-2;//源点的父节点需特殊标示   
    min_flow[s]=INF;
    q.push(s);
    while(!q.empty()){//BFS寻找增广路径   
      int tmp=q.front();q.pop();
      for(int i=0;i<num;++i){
        if(f[i]==-1 && flow[tmp][i]<map[tmp][i]){//当结点i还未被探索到,并且还有可用流量 
          q.push(i);
          f[i]=tmp;
          min_flow[i]=min(min_flow[tmp],(map[tmp][i]-flow[tmp][i]));
        }
      }
      if(f[t]!=-1){//t的父节点不为初始值,说明BFS已经找到了一条路径   
        int k=t;
        while(f[k]>=0){
          flow[f[k]][k]+=min_flow[t];//将新的流量加入flow
          flow[k][f[k]]=-flow[f[k]][k];
          k=f[k];
        }
        break;
      }
    }
    if(f[t]==-1)return ans;//不存在增广路径,返回   
    else ans+=min_flow[t];
  }
}
int main(int argc, char *argv[])
{
  while(scanf("%d%d",&n,&m)!=EOF){
    int a,b,ans;
    memset(map,0,sizeof(map));
    for(int i=0;i<n;++i){
      map[i][i+n]=1;
    }
    for(int j=0;j<m;++j){
      scanf(" (%d,%d)",&a,&b);
      map[b+n][a]=map[a+n][b]=INF;
    }
    ans=INF;
    for(int i=1;i<n;++i){
      ans=min(ans,max_flow(n*2,n,i));
    }
    if(ans==INF)ans=n;
    printf("%d/n",ans);
  }
  return 0;
}


  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值