POJ - 1966 Cable TV Network (最大流求点连通度)

时间:2024-01-14 10:00:02

题意:求一个无向图的点连通度。点联通度是指,一张图最少删掉几个点使该图不连通;若本身是非连通图,则点连通度为0。

分析:无向图的点连通度可以转化为最大流解决。方法是:1.任意选择一个点作为源点;2.枚举所有与该点间没有边的点作为汇点;3.将每个点拆为入点和出点,入点到出点建一条流量为1的边;4.原本有边关系的两点,建流量为正无穷的双向边;5.每次跑出最大流,其中最小值即点连通度,若最小值为正无穷,则说明点连通度为|顶点数|。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2+5; bool vis[maxn];
struct Edge{
int from, to,cap,flow;
};
struct Dinic
{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn]; void init(int n){
this->n = n;
for(int i=0;i<=n;++i){
G[i].clear();
}
edges.clear();
} void AddEdge(int from,int to,int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
} bool BFS(){
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
d[s] = 0;
vis[s] = 1;
while(!q.empty()){
int x = q.front(); q.pop();
for(int i=0;i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(!vis[e.to] && e.flow < e.cap){
vis[e.to] = 1;
d[e.to] = d[x] + 1;//层次图
q.push(e.to);
}
}
}
return vis[t];//能否到汇点,不能就结束
}
int DFS(int x,int a)//x为当前节点,a为当前最小残量
{
if(x == t || a == 0) return a;
int flow = 0 , r;
for(int& i = cur[x];i < G[x].size();i++){
Edge& e = edges[G[x][i]];
if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 ){
e.flow += r;
edges[G[x][i] ^ 1].flow -= r;
flow += r;//累加流量
a -= r;
if(a == 0) break;
}
}
return flow;
}
int MaxFlow(int s,int t){
this->s = s; this->t = t;
int flow = 0;
while(BFS()){
memset(cur,0,sizeof(cur));
flow += DFS(s,INF);
}
return flow;
}
}F; int G[maxn][maxn]; int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int N,M;
while(scanf("%d %d",&N,&M)==2){
int u,v,st=N; //任选一点为源点,此处选择0
for(int i=0;i<N;++i){
G[i][i] = 1;
for(int j=i+1;j<N;++j)
G[i][j] = G[j][i] = 0;
}
for(int i=1;i<=M;++i){
scanf(" (%d,%d)",&u,&v);
G[u][v] = G[v][u] = 1;
}
int ans = INF;
for(int i=0;i<N;++i){ //枚举汇点
if(G[0][i]) continue;
F.init(2*N);
for(int j=0;j<N;++j){
F.AddEdge(j,j+N,1); //拆点 [0,N-1]为入点,[N,2N-1]为出点
}
for(int j=0;j<N;++j){
for(int k=j+1;k<N;++k){
if(G[j][k]){
F.AddEdge(j+N,k,INF);
F.AddEdge(k+N,j,INF);
}
}
}
ans = min(ans,F.MaxFlow(st,i));
}
if(ans==INF) ans = N;
printf("%d\n",ans);
}
return 0;
}