刚刚又写了一遍UVA 315,之前看着别人的代码写过一次,大概就是这周四才写的,刚刚写发现判断条件完全忘记了···难受,原来我忘东西忘的这么快,之后要找个时间把之前的题再复习一下啊,可是就剩三个星期就要省赛了,心态炸裂·····
这篇是用tarjan算法来找割点
割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点。
对于一个连通图,如果v不经过u就无法达到u的祖先节点,那么u就是一个割点,因为删去u之后,v就与u的祖先节点分开了,一个连通图变成了两个子图(对于有向图我们先不讨论,我现在甚至都不明白有向图到底有没有割点的概念,而且有向图的连通性判断也和无向图不太一样,啊,好想再上一年的离散数学课啊),根据这个定义,我们转化成tarjan算法中表示的话就是,low[v]>=dfn[u](这里为什么不是low[v]>=low[u],很显而易见,low[u]可能更新之后变成了包含u的搜索树的最小的根节点的数值,而v可能有条路到u的祖先,但是还不足以到达low[u],这种情况会把u误判为割点),low[v]>=dfn[u]代表,v没有一条路可以到达u的祖先,很明显,如果有这样的路,low[v]就会更新为dfn[u的祖先]。
注意这里如果v是根节点,那么由于它没有父亲节点,所以需要特判,如果以根节点为根的搜索树大于1的话,那么根节点就是一个割点。
感觉写的好乱啊,而且其中有很多东西真的不太容易用语言表达,画个图看看能理解的更清楚,下面贴UVA 315
Description
![Download as PDF Download as PDF](https://i-blog.csdnimg.cn/blog_migrate/2ea975a8d421ce3226c46b0946fd5932.png)
A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N. No two places have the same number. The lines are bidirectional and always connect together two places and in each place the lines end in a telephone exchange. There is one telephone exchange in each place. From each place it is possible to reach through lines every other place, however it need not be a direct connection, it can go through several exchanges. From time to time the power supply fails at a place and then the exchange does not operate. The officials from TLC realized that in such a case it can happen that besides the fact that the place with the failure is unreachable, this can also cause that some other places cannot connect to each other. In such a case we will say the place (where the failure occured) is critical. Now the officials are trying to write a program for finding the number of all such critical places. Help them.
Input
The input file consists of several blocks of lines. Each block describes one network. In the first line of each block there is the number of places N < 100. Each of the next at most N lines contains the number of a place followed by the numbers of some places to which there is a direct line from this place. These at most N lines completely describe the network, i.e., each direct connection of two places in the network is contained at least in one row. All numbers in one line are separated by one space. Each block ends with a line containing just 0. The last block has only one line with N = 0.
Output
The output contains for each block except the last in the input file one line containing the number of critical places.
Sample Input
5
5 1 2 3 4
0
6
2 1 3
5 4 6 2
0
0
Sample Output
1
2
题意:给你一些连通块,让你找出有几个割点
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Maxn 105
int head[Maxn];
int u[Maxn*Maxn];
int v[Maxn*Maxn];
int _next[Maxn*Maxn];
int dfn[Maxn];
int low[Maxn];
int re[Maxn];
int ans;
void dfs(int k,int num,int root,int fa){
int cnt=0;
dfn[k]=low[k]=num;
for(int i=head[k];i!=-1;i=_next[i]){
int e=v[i];
if(!dfn[e]) {
cnt++;
dfs(e,++num,root,k);
low[k]=min(low[e],low[k]);
if(k!=root &&dfn[k]<=low[e]) re[k]=1; //这里必须确保<u,v>是树枝边,否则low[e]可能更新过,导致误判(和为什么不能是low[k]<=low[e]相似)
else if(k==root&&cnt>1) re[k]=1;//对于根节点要特判,如果根节点有多个子树,那么是割点
}
else low[k]=min(low[k],dfn[e]);
}
}
int main(){
int n;
while(scanf("%d",&n)&&n){
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(re,0,sizeof(re));
ans=0;
int s,t;
int c=0;
while(scanf("%d",&s)&&s){
while(getchar()!='\n'){
scanf("%d",&t);
u[c]=s;
v[c]=t;
_next[c]=head[s];
head[s]=c++;
u[c]=t;
v[c]=s;
_next[c]=head[t];
head[t]=c++;
}
}
for(int i=1;i<=n;i++){
if(!dfn[i]) dfs(i,1,i,-1);
}
for(int i=1;i<=n;i++) if(re[i]) ans++;
printf("%d\n",ans);
}
}