HLG 1542 Bombs of HRBUST(Ⅱ)(点连通度)
题意: 恐怖分子在去年轰炸哈理工未遂后,打算今年卷土重来,学校为了预防恐怖分子潜入主楼,决定在今年9月份在每间教室安装摄像头,恐怖分子为了能够成
功潜入主楼,将要摧毁这些摄像头。
已知摄像头的安装是成网络状的,摄像头的连接是双向的。如果网络中任何两个摄像头之间至少有一条路,则该网络为连通的,否则不连通。一个空的网络
或只有一个摄像头的网络被认为是连通的。如果网络不连通,则导致摄像头主系统瘫痪,恐怖分子会成功潜入主楼。因为摄像头之间的连线是接在墙里的,
所以只能靠摧毁摄像头使网络不连通,做为恐怖分子头目的你,请你计算至少要摧毁多少个摄像头才能让你的手下成功潜入主楼。
分析:使得网络不连通所需去除的最少的点的个数即为该图的点连通度,这题只要枚举起点汇点找到最小连通度即可。
连通度总结:
图的连通度问题是指:在图中删去部分元素(点或边),使得图中指定的两个点s和t不连通(不存在从s到t的路径),求至少要删去几个元素。
图的连通度分为点连通度和边连通度:
(1)点连通度:只许删点,求至少要删掉几个点(当然,s和t不能删去,这里保证原图中至少有三个点);
图的连通度分为点连通度和边连通度:
(1)点连通度:只许删点,求至少要删掉几个点(当然,s和t不能删去,这里保证原图中至少有三个点);
(2)边连通度:只许删边,求至少要删掉几条边。
并且,有向图和无向图的连通度求法不同,因此还要分开考虑(对于混合图,只需将其中所有的无向边按照无向图的办法处理、有向边按照有向图的办法处理即可)。
【1】有向图的边连通度:
这个其实就是最小割问题。以s为源点,t为汇点建立网络,原图中的每条边在网络中仍存在,容量为1,求该网络的最小割(也就是最大流)的值即为原图的边连通度。
【2】有向图的点连通度:
需要拆点。建立一个网络,原图中的每个点i在网络中拆成i'与i'',有一条边<i', i''>,容量为1(<s', s''>和<t', t''>例外,容量为正无穷)。原图中的每条边<i, j>在网络
并且,有向图和无向图的连通度求法不同,因此还要分开考虑(对于混合图,只需将其中所有的无向边按照无向图的办法处理、有向边按照有向图的办法处理即可)。
【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】)处理。
最大流对应的是最小割。显然,容量为正无穷的边不可能通过最小割,也就是原图中的边和s、t两个点不能删去;若边<i, i''>通过最小割,则表示将原图中的点i删去。
【3】无向图的边连通度:
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【1】)处理;
【4】无向图的点连通度:
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【2】)处理。
#include<stdio.h> #include<string.h> #define INF 0x1f1f1f1f #define clr(x)memset(x,0,sizeof(x)) #define min(a,b)(a)<(b)?(a):(b) int gap[105]; int dis[105]; int c[105][105]; void init(int s,int u,int n) { int v,x,front=0,rear=0; int q[105]; clr(gap); memset(dis,0xff,sizeof(dis)); q[rear++]=u; dis[u]=0; while(front<rear) { x=q[front++]; gap[dis[x]]++; for(v=0;v<=n;v++) if(dis[v]==-1&&c[v][x]>0) { dis[v]=dis[x]+1; q[rear++]=v; } } } int sap(int s,int u,int n) { init(s,u,n); int flag,flow=0,top=s,i,j,k; int pre[105]; int low[105]; while(dis[s]<=n) { flag=0; low[s]=INF; for(i=0;i<=n;i++) if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0) { flag=1; break; } if(flag) { low[i]=c[top][i]; low[i]=min(low[i],low[top]); pre[i]=top; top=i; if(top==u) { flow+=low[u]; j=top; while(j!=s) { k=pre[j]; c[k][j]-=low[u]; c[j][k]+=low[u]; j=k; } top=s; clr(low); } } else { int dmin=n; for(j=0;j<=n;j++) if(c[top][j]>0&&dis[j]+1<dmin&&dis[j]>=0) dmin=dis[j]+1; gap[dis[top]]--; if(gap[dis[top]]==0) break; gap[dmin]++; dis[top]=dmin; if(top!=s) top=pre[top]; } } return flow; } struct node { int from,to; }e[100000]; int main() { int n,m,i,j,res,tmp,a,b,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<m;i++) { scanf(" (%d,%d)",&a,&b); e[i].from=a; e[i].to=b; } res=INF; for(i=0;i<n;i++) { for(k=i+1;k<n;k++) { clr(c); for(j=0;j<n;j++) c[j][j+n]=1; for(j=0;j<m;j++) { c[e[j].from+n][e[j].to]=INF; c[e[j].to+n][e[j].from]=INF; } tmp=sap(n+i,k,n*2-1); if(tmp<res) res=tmp; } } if(res>=n) printf("%d\n",n); else printf("%d\n",res); } return 0; }