题意:给定一个无向图,求最少删去多少个点可以使图不连通。
思路:根据Menger定理(图的连通度为k,则任意点间必有k条不相交路径),这样建图,首先将每个点拆成两个点,每个点可以表示成i与i+n。那么有向边<i,i+n>的容量为1,如果i与j相邻,那么有有向边<i+n,j>=<j+n,i>=INF。然后枚举源点和汇点求最大流。如果最大流都是INF,那么代表这个图是一个完全连通图,最小割点集为n;否则就输出最大流。
此题不枚举点对,固定源点枚举汇点也能过,实际上是有问题的。如3个点的路径:1、0、2。如果固定0为源点,那么0到点1和点2的最大流都是INF,会输出3,实际上应该输出1.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x1fffffff
#define N 105
int n,m;
int f[N][N],c[N][N],a[N],p[N],q[N<<3];
int maxflow(int s,int t){
int i,j,res=0,front,rear;
memset(f, 0,sizeof(f));
while(1){
memset(a, 0, sizeof(a));
a[s] = INF;
memset(p, 0, sizeof(p));
front = rear = -1;
q[++rear] = s;
while(front < rear){
i = q[++front];
for(j = 0;j<2*n;j++)
if(!a[j] && c[i][j]-f[i][j]>0){
a[j] = min(a[i],c[i][j]-f[i][j]);
q[++rear] = j;
p[j] = i;
}
}
if(!a[t])
break;
res += a[t];
for(i = t;i!=s;i=p[i]){
f[p[i]][i] += a[t];
f[i][p[i]] -= a[t];
}
}
return res;
}
int main(){
while(scanf("%d %d",&n,&m) != EOF){
int i,j,a,b,res = INF;
memset(c,0,sizeof(c));
if(!n){ //特判一下n为0和1的情况
printf("0\n");
continue;
}else if(n==1){
printf("1\n");
continue;
}
for(i = 0;i<n;i++)
c[i][i+n] = 1;
for(i = 1;i<=m;i++){
scanf(" (%d,%d)",&a,&b);
c[a+n][b] = INF;
c[b+n][a] = INF;
}
for(i = 0;i<n-1;i++) //枚举所有点对
for(j = i+1;j<n;j++)
if(!c[i+n][j])
res = min(res,maxflow(i+n,j));
/*for(i = 1;i<n;i++){
res = min(res,maxflow(n, i));//此题这样也能过,但是我觉得这是不妥的。如3个点的路径1、0、2。
}*/
if(res == INF)
printf("%d\n",n);
else
printf("%d\n",res);
}
return 0;
}