题意:给定一个无向图,判断是否是一个caterpillar。是caterpillar的条件是:一,无环连通图。二,存在一条'脊柱',使所有的点要么在‘脊柱’上,要么与在‘脊柱’上的点相连。
思路:可用并查集判断是否是无环连通图,若有环则无法成功合并两个点,若非连通图则最后所有点的父节点不会是同一个。接着判断是否含有“脊柱”,只需要将每个分支点中与之相连的度为1的点删除掉,全部删掉之后,看剩下的点的度是否小于等于2即可,如果某点的度大于2,则说明它至少连了两个度不为1的分支,则这必定不是一个“脊柱”。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
const int maxn = 1e9;
const int maxt = 1e8;
const double eps = 1e-6;
typedef long long ll;
const ll MOD = 1e9;
const int inf = 0x3f3f3f3f3f;
set<int> s[110];
int d[110][110];
int f[110];
int tmp_len[110];
int n, e;
int Find(int x)//寻找点x的父节点
{
return x == f[x] ? x : f[x] = Find(f[x]);
}
bool Union(int x, int y)//合并两点
{
int fx = Find(x);
int fy = Find(y);
if(fx == fy) return false;//有环
if(fx < fy)//使其父节点相同。若为联通图则最后所有点的父节点应该是同一个
f[fy] = fx;//有个地方没太弄懂,如果不分大小情况的话最后所有点的父节点是不相同的,只有这样分了大小以后联通图所有点的父节点才相同
else
f[fx] = fy;
return true;
}
bool judge()//判断是否含有”脊柱“
{
set<int> :: iterator it;
for(int i = 1; i <= n; i++)
{
int len = s[i].size();
if(len > 1)//找到度大于1的点,即含有分支的点
{
tmp_len[i] = len;//记录点i当前的度数顺便标记是否访问过该点(访问过,才会给其赋值)
for(it = s[i].begin(); it != s[i].end(); it++)//遍历与该点相连的所有的点
{
int u = *it;
if(tmp_len[u]) continue;//访问过该点,跳过
if(s[u].size() == 1)//删除与之相连的度为1的点
{
tmp_len[i]--;//点i的度数减一
d[i][u] = d[u][i] = 0;//u i 两点不再相连
}
}
}
}
bool ok = true;
for(int i = 1; i <= n; i++)
{
if(tmp_len[i] > 2)//若经过上面的删除操作后还有度大于2的点,则不是”脊柱“
{
ok = false;
break;
}
}
return ok;
}
int main()
{
int kase = 0;
while(~scanf("%d",&n) && n)
{
memset(f, 0, sizeof(f));//记录每个点的父节点
memset(d, 0, sizeof(d));//标记u v两点是否相连,相连为1,否则为0
memset(tmp_len, 0, sizeof(tmp_len));
for(int i = 0; i <= n; i++)
s[i].clear();
for(int i = 1; i <= n; i++)
f[i] = i;//初始时所有点的父节点使其本身
scanf("%d",&e);
int u, v;
for(int i = 0; i < e; i++)
{
scanf("%d%d",&u,&v);
s[u].insert(v);
s[v].insert(u);
d[u][v] = 1;//标记u v 两点相连
}
bool ok = true;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(d[i][j] && !Union(i, j))//若U V 两点相连并且可以合并,则说明该图为无环图
{
ok = false;
break;
}
}
}
if(ok == true)//判断是否是连通图,即所有点的父节点是否相同
{
for(int i = 2; i <= n; i++)
if(f[i] != f[i - 1])
{
ok = false;
break;
}
}
if(!ok)
{
printf("Graph %d is not a caterpillar.\n",++kase);
continue;
}
if(judge())
printf("Graph %d is a caterpillar.\n",++kase);
else
printf("Graph %d is not a caterpillar.\n",++kase);
}
return 0;
}