[POJ 3310][树的直径]Caterpillar

该博客讨论了如何判断一个无向图是否为具有特定特性的‘毛毛虫’图,即图是连通且无环,并存在一条路径,所有节点要么在这条路径上要么与之相邻。博主通过实现求树直径的方法来解决这个问题,并提供了输入格式、题目分析以及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:
题目链接: poj 3310 Caterpillar
Description

An undirected graph is called a caterpillar if it is connected, has no cycles, and there is a path in the graph where every node is either on this path or a neighbor of a node on the path. This path is called the spine of the caterpillar and the spine may not be unique. You are simply going to check graphs to see if they are caterpillars.

For example, the left graph below is not a caterpillar, but the right graph is. One possible spine is
shown by dots.

Input

There will be multiple test cases. Each test case starts with a line containing n indicating the number of nodes, numbered 1 through n (a value of n = 0 indicates end-of-input). The next line will contain an integer e indicating the number of edges. Starting on the following line will be e pairs n1 n2 indicating an undirected edge between nodes n1 and n1. This information may span multiple lines. You may assume that n ≤ 100 and e ≤ 300. Do not assume that the graphs in the test cases are connected or acyclic.

Output

For each test case generate one line of output. This line should either be

Graph g is a caterpillar.

or

Graph g is not a caterpillar.

as appropriate, where g is the number of the graph, starting at 1.

Sample Input

22
21
1 2 2 3 2 4 2 5 2 6 6 7 6 10 10 8 9 10 10 12 11 12 12 13 12 17 18 17 15 17 15 14 16 15 17 20 20 21 20 22 20 19
16
15
1 2 2 3 5 2 4 2 2 6 6 7 6 8 6 9 9 10 10 12 10 11 10 14 10 13 13 16 13 15
0

Sample Output

Graph 1 is not a caterpillar.
Graph 2 is a caterpillar.

题目大意:
判断一个图是否是一棵树(是否全部连通并且不存在环),并且满足条件,存在一条链,使得所有点要么在链上要么与链上的点距离为1。
输入格式,多组输入数据,每一组,第一行个数n,第二行边数m,第三行共m对(2*m个),每一对的数字是点的编号,表示这两个点之间连一条边。
题目分析:
这道题做法多样,但是我是为了用来练习树的直径,所以用的是求树的直径的写法,虽然代码量会比有的解法大一点。判断是否是一棵树可以用dfs。证明为什么这条链是树的直径:假设存在这样一条链,那么所有非此链上的点到此链的距离都为1,所以并不会存在一条更长的链,这条链就是最长的,即为树的直径。标记出这条链,最后判断一下所有点是否满足条件。
PS:不了解树的直径的同学,请戳:树的直径求法及证明
附代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

int n,m,x,y,tot,to[1000],nxt[1000],first[200];
int dis[200],bj[200],maxd,po,t;
bool check,flag,vis[200]; 

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

void create(int x,int y)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
}

void dfs1(int u,int fa)//判是不是一棵树
{
    vis[u]=true;
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v!=fa)
        {
            if(vis[v]==true) {check=true;return;}
            dfs1(v,u);
            if(check==true) return;
        }
    }
}

void dfs2(int u,int fa)//求树的直径
{
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v!=fa)
        {
            dis[v]=dis[u]+1;
            bj[v]=dis[v];
            if(dis[v]>maxd) {maxd=dis[v];po=v;}//maxd记录最长的路径长
            dfs2(v,u);
            bj[u]=max(bj[u],bj[v]);//记录儿子所能传递回来的最大值,就可以标记出树的直径这条链
        }                         //因为这条链上的bj都会等于maxd,而非链上的都会小于maxd
    }
}

int main()
{
    //freopen("lx.in","r",stdin);

    while(n=readint(),n!=0)
    {
        t++;
        check=false;
        tot=0;
        memset(vis,false,sizeof(vis));
        memset(first,0,sizeof(first));
        m=readint();
        for(int i=1;i<=m;i++)
        {
            x=readint();
            y=readint();
            create(x,y);
            create(y,x);
        }
        if(m>n-1) check=true;//边数大于点数加1,则绝对不可能是一棵树
        if(check==false) dfs1(1,0);
        if(check==false)
        {
            for(int i=1;i<=n;i++)
            if(vis[i]==false)//如果存在没有搜到的点
            {
                check=true;
                break;
            }
            if(check==false)
            {
                maxd=0;
                memset(dis,0x3f3f3f3f,sizeof(dis));
                memset(bj,0,sizeof(bj));
                dis[1]=0;
                dfs2(1,0);//求出树的直径的一个端点
                dis[po]=0;
                dfs2(po,0);//寻找到链
                for(int i=1;i<=n;i++)
                {
                    flag=false;
                    if(bj[i]==maxd) continue;//链上的点
                    for(int e=first[i];e;e=nxt[e])
                        if(bj[to[e]]==maxd) {flag=true;break;}//此点有一个出边指向链上的点
                    if(flag==false) {check=true;break;}
                }
            }
        }
        if(check==true) printf("Graph %d is not a caterpillar.\n",t);
        else printf("Graph %d is a caterpillar.\n",t);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值