您的位置:首页 > 其它

POJ 1144

2016-11-27 22:18 190 查看
题目的意思是要你求出给定的图中有几个关节点。
何为关节点?  简单来说就是在一个完整的图中,如果失去某个结点,这个图将不会完整,会分成几个小图。
我的思路是这样的: 假设这个点是关结点,那么它被删除之后,图的个数肯定会增加,该图至少变成两个图,也就是说存在两个结点的前驱不存在。
我们可以先把图进行深度优先遍历或广度优先遍历,这样我们会得到一组数据存入一个数组中。给结点定义一个结构体,设有前驱和后继并指明该结点的前驱跟后继分别是什么。当然根结点是没有前驱的。  我们可以根据遍历得到的数据顺序依次删除,在删除该结点之后,修改该结点对应的前驱和后继的结点的后继和前驱。然后对图中的前驱为空的结点个数进行判断,若大于1该结点为关结点。 依次类推,每个结点进行判断一次。但是我没有写出对应的代码,下面的代码是用了网友的, 注释是我加的 ,可能有些不对,希望各位指正。

一个结点是否为关节点有两种特征:若他是根结点,则它的子树肯定是大于等于2的。若他是非叶子节点,则它所对应的子树必须通过它才能联系到根。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include<iostream>

#include<stdlib.h>

#include<string.h>

using namespace std;

#define max 100

#define Min(a,b) (a<b?a:b)

#define Max(a,b) (a>b?a:b)

int n, ans;

int map[max][max]; //用来存储输入的顶点

bool isvisted[max]; //用来记录哪些顶点已经访问过了

int gpoint[max];//用来存储判断完不是根结点的结点

int index, root;//被搜索的次数,根结点

int DFN[max], low[max];//表示深度优先搜索某结点,表示某结点子树中的最小序号

void tarjan(int u)

{

DFN[u] = low[u] = ++index;

isvisted[u] = true;//设定该结点已经被访问过

int i;

for ( i = 1; i <=n; ++i)

{

if (map[u][i])

{

if (!isvisted[i])//该边有条顶点没有被访问过,继续根据该顶点搜索下去

{

tarjan(i);

low[u] = Min(low[u], low[i]);//更新当前子树中的最小序号

if (low[i]>=DFN[u] && u!=1)//表示只有通过u才能访问u的祖先 一定要有等于号 不然会丢失结点为树根的情况

{

gpoint[u]++;

}

else if (u==1)//表示该结点是根结点

{

root++;

}

}

else//表示已经访问过该节点

{

low[u] = Min(low[u], DFN[i]);

}

}

}

}

int main()

{

while (scanf("%d",&n)&&n)//确定有几个节点数

{

int u, v;

memset(map,0,sizeof(map));

memset(isvisted, false, sizeof(isvisted));

memset(gpoint, 0, sizeof(gpoint));

ans = root = index = 0;

while (scanf("%d",&u)&&u)//u代表某一具体的结点

{

while (getchar()!='\n')

{

scanf("%d", &v);//与u对应的边的另一结点

map[u][v] = 1;

map[v][u] = 1;

}

}

tarjan(1);

if (root>1)

{

ans++;

}

for (int i = 2; i <=n; ++i)//前面已经判断过根结点是否为关节点,只要从搜索顺序的第二结点进行判断即可

{

if (gpoint[i])

{

ans++;

}

}

printf("%d\n", ans);

}

system("pause");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: