首页 > 代码库 > 图的割点 | | jzoj【P1230】 | | gdoi | |备用交换机
图的割点 | | jzoj【P1230】 | | gdoi | |备用交换机
写在前面:我真的不知道图的割点是什么。。。。
看见ftp图论专题里面有个dfnlow的一个文档,于是怀着好奇的心情打开了这个罪恶的word文档,,然后就开始漫长的P1230的征讨战。。。。
图的割点是这样的:
path1=暴力
枚举每一个点,如果去掉这个点就可以使图断开,那么这个点就是割点(时间复杂度O(N(N+M)))
path2=tarjan
从任意一个点开始遍历,记录遍历的顺序,然后对正在遍历的点进行一次深度优先遍历,但是此次遍历不允许经过这个点,看看还能不能回到前一个点
这时候我们就可以再定义一个数组low,这个数组用来记录每个顶点在不经过前一个遍历的顶点时,能够回到的最近(就是截止到此顶点最后被遍历)的结点
如果存在一个顶点u,图中一个顶点v满足low[v]>=num[u](num是遍历的顺序),那么u就是割点
problem set:
n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接。因电子设备容易损坏,需给通讯点配备备用交换机。但备用 交换机数量有限,不能全部配备,只能给部分重要城市配置。于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备 用交换机。请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换机城市的编号。
很明显这个题是割点:
但是有一个坑~~
最开始写的是邻接矩阵,,看看能不能过,想着邻接矩阵能过小数据以后改成邻接表就能过大数据了
然而最开始还是too young
别忘了题目描述里并没有说图一定联通;
也就是说我们必须对每一个点都进行遍历,而且不要忘了对根节点的判断。。。
代码实现如下
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;int n,m,root;int num[500000],low[500000],flag[500000],index;//index==++int in[500000],stack[500000];int sum=0;struct edge{ int y,next;}e[500000];int len=0;int link[500000];void insert(int xx,int yy){ e[++len].next=link[xx];link[xx]=len; e[len].y=yy; }int top;void dfs(int cur){ int v; num[cur]=low[cur]=++index; stack[++top]=cur; in[cur]=1; int temp=0; for(int i=link[cur];i;i=e[i].next) { v=e[i].y; if(!num[v]) { dfs(v); temp++; low[cur]=min(low[cur],low[v]); //if(low[v]>=num[cur]&&cur!=1) // flag[cur]++; if((cur==root && temp>1)||(cur!=root && low[v]>=num[cur])) if(!flag[cur]) flag[cur]++,sum++; } else if(in[v]) low[cur]=min(low[cur],num[v]); } if(low[cur]==num[v]) { while(cur!=v) { v=stack[top--]; in[v]=0; } }}int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int x,y; cin>>n; while(cin>>x>>y) { insert(x,y); insert(y,x); } for(int i=1;i<=n;i++) { if(!num[i]) { root=i; dfs(i); } } cout<<sum<<endl; for(int i=1;i<=n;i++) { if(flag[i]) cout<<i<<endl; } return 0;}
图的割点 | | jzoj【P1230】 | | gdoi | |备用交换机