题目: SPF
题意:给一个网络(实质是一副无向图),每一个节点为一台计算机,输出:哪一台计算机是割点 , 移去它之后网络被分成了几块
思路:无向图求割点套模板,所谓割点(参考):
1.如果点v是DFS序列的根节点,则如果v有一个以上的孩子,则v是一个割点。
2.如果v不是DFS序列根节点,并且点v的任意后继u能追溯到最早的祖先节点low[u]>=dfn[v],则v是一个割点。
用当前子节点计数器count统计去掉割点后的连通分支,如果是dfs根节点则为count,否则为count+1
代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+100;
#define eps 1e-14
struct node
{
int now;
int next;
}e[1010];
int head[1010] , vis[1010] , low[1010] , dfn[1010], cnt , clo , set[1010];
void add(int x , int y)
{
e[cnt].now = y;
e[cnt].next = head[x];
head[x] = cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(set,0,sizeof(set));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
clo=0;
cnt=0;
}
void gedian(int fa , int cur)
{
int count=0; //当前点的孩子数
dfn[cur] = low[cur] = ++clo;
vis[cur] = 1;
for(int i = head[cur] ; i!=-1 ; i = e[i].next)
{
int now = e[i].now;
if(!vis[now])
{
gedian(cur,now);
count++;
if(low[now] < low[cur]) //更新cur的祖先:若cur的子节点能追溯到更早的祖先,则cur也能追溯到
low[cur] = low[now];
if(!fa && count>1) //判断条件1
set[cur] = count;
else if(fa && dfn[cur] <= low[now]) //判断条件2
set[cur] = count+1;
}
else if(now != fa && low[cur] > low[now])//若已被访问,更新更早祖先
low[cur] = low[now];
}
}
int main()
{
int a,b;
int kase=1;
while(~scanf("%d",&a) && a)
{
init();
do
{
scanf("%d",&b);
add(a,b);
add(b,a);
scanf("%d",&a);
}while(a);
if(kase!=1)
puts("");
gedian(0,1);
printf("Network #%d\n",kase++);
bool ok = false;
for(int i = 0 ; i < 1010 ; i++)
if(set[i])
{
ok = true;
printf(" SPF node %d leaves %d subnets\n" , i , set[i]);
}
if(!ok)
printf(" No SPF nodes\n");
}
return 0;
}