POJ 1144

题目的意思是要你求出给定的图中有几个关节点。
何为关节点?  简单来说就是在一个完整的图中,如果失去某个结点,这个图将不会完整,会分成几个小图。
我的思路是这样的: 假设这个点是关结点,那么它被删除之后,图的个数肯定会增加,该图至少变成两个图,也就是说存在两个结点的前驱不存在。
我们可以先把图进行深度优先遍历或广度优先遍历,这样我们会得到一组数据存入一个数组中。给结点定义一个结构体,设有前驱和后继并指明该结点的前驱跟后继分别是什么。当然根结点是没有前驱的。  我们可以根据遍历得到的数据顺序依次删除,在删除该结点之后,修改该结点对应的前驱和后继的结点的后继和前驱。然后对图中的前驱为空的结点个数进行判断,若大于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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值