想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:给你一个无向图,这个图有一个安全系数f,
f的定义是:
1.f为n,如果不管删除多少个顶点,剩下的图仍然是连通的
2.f为删除最少的顶点数,使得剩下的图不连通
给你一个图,求出f
解题思路:题目给出的目标很明显,转换成图,那么f就是无向图中的连通度吗,或者说,是求无向图中的最小割点集。
根据Menger定理,这样建图,首先将每个点拆成两个点
每个点可以表示成i与i+n
那么有向边<i,i+n>的容量为1
如果i与j相邻,那么有有向边<i+n,j>=<j+n,i>=INF,等于无穷大
然后固定源点,枚举汇点求最大流。如果最大流都是INF,那么代表这个图是一个完全连通图,最小割点集为n
否则就输出最大流。
/* Memory 272K Time 47MS */ #include <iostream> #include <queue> using namespace std; #define MAXV 110 #define INF 1<<29 #define min(a,b) (a>b?b:a) int map[MAXV][MAXV],flow[MAXV][MAXV]; int parent[MAXV]; //用于bfs寻找路径 int bfs(int n,int start,int end){ int a[MAXV],i,v; queue <int>q; memset(a,0,sizeof(a)); //记录增广路最小流量,而且又可以当做广搜的标记数组 memset(parent,-1,sizeof(parent)); //记录下这条增广路,以便增流 q.push(start); a[start]=INF; while(!q.empty()){ v=q.front();q.pop(); for(i=0;i<n;i++){ if(!a[i] && map[v][i]>flow[v][i]){ //如果这是一条允许弧就记录下来 q.push(i); parent[i]=v; a[i]=min(a[v],map[v][i]-flow[v][i]); } } if(v==end) break; //找到增广路退出 } return a[end]; } int EdmondsKarp(int n,int sp,int fp){ int i,tmp; int maxflow=0; memset(flow,0,sizeof(flow)); while(tmp=bfs(n,sp,fp)){ for(i=fp;i!=sp;i=parent[i]){ //根据父亲数组更新流量 flow[i][parent[i]]-=tmp; //更新反向流 flow[parent[i]][i]+=tmp; //更新正向流 } maxflow+=tmp; } return maxflow; } int main(){ int i,a,b; int n,m; while(~scanf("%d %d",&n,&m)){ memset(map,0,sizeof(map)); for(i=0;i<n;i++) map[i][i+n]=1; for(i=0;i<m;i++){ scanf(" (%d,%d)",&a,&b); map[a+n][b]=map[b+n][a]=INF; } int ans=INF; for(i=1;i<n;i++){ ans=min(ans,EdmondsKarp(n*2,n,i)); } if(ans==INF) printf("%d\n",n); else printf("%d\n",ans); } return 0; }