zoukankan      html  css  js  c++  java
  • 「日常训练」Caterpillar(POJ-3310)

    题意与分析

    一条很有趣的题目。给一个无向图,问它是否无环,且可以在上面找到一条线,使所有的顶点要么在线上要么不在线上但在与线相连的边上。
    那么首先要确定所有点联系在一起。这个可以同判环一起处理:如果建图新加入的点同原先的点含有同一个祖先,那它肯定是环没跑了。然后遍历所有节点,看看是否拥有同一个祖先。这样就完成了两个任务。
    接下来需要一点分析:我们可以证明,这条线(如果存在)一定是树的直径,或者是与树的直径长度相等(在端点差一个点那边分的叉)。为什么?如果这条线不是树的直径,那么长度一定小于直径,且树的直径与它的交点一定至少会延伸出两个点,那么这就一定会翻车,这条线一定不会满足条件。所以如果有一条线满足这个条件,那它必须得是树的直径。然后就是之前知识学习的地方,先找树的直径(这里需要记录端点,我没有采用栈的方法记录,采用了一种比较简单的方法解决),然后判断非树直径的点是否度数为1即可。
    这题综合考察了树的几个性质,非常适合学习/复习。比如说我竟然忘了并查集怎么判环- -

    代码

    /* 
     * Filename: poj3310.cpp
     * Date: 2018-11-05
     */
    #include <iostream>
    #include <cstring>
    #include <vector>
    
    #define INF 0x3f3f3f3f
    #define PB push_back
    #define MP make_pair
    #define fi first
    #define se second
    #define rep(i,a,b) for(repType i=(a); i<=(b); ++i)
    #define per(i,a,b) for(repType i=(a); i>=(b); --i)
    #define ZERO(x) memset(x, 0, sizeof(x))
    #define MS(x,y) memset(x, y, sizeof(x))
    #define ALL(x) (x).begin(), (x).end()
    
    #define QUICKIO                  
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
    
    using namespace std;
    typedef int repType;
    
    const int MAXN=105;
    vector<int> G[MAXN];
    
    int pa[MAXN],n;
    int find_pa(int x)
    {
        return pa[x]==x?x:pa[x]=find_pa(pa[x]);
    }
    bool union_pa(int x,int y)
    {
        int fx=find_pa(x),
            fy=find_pa(y);
        if(fx!=fy) pa[fx]=fy;
        else return false;
        return true;
    }
    
    bool judge_cnt()
    {
        int cnt=0;
        rep(i,1,n)
            if(pa[find_pa(i)]==i) cnt++;
        return cnt==1;
    }
    
    int dep[MAXN];
    void dfs(int x)
    {
        rep(i,0,int(G[x].size())-1)
            if(dep[G[x][i]]==-1)
            {
                dep[G[x][i]]=dep[x]+1;
                dfs(G[x][i]);
            }
    }
    bool on_road[MAXN];
    bool on_road_tmp[MAXN];
    int maxdep=0;
    void dfs2(int now, int ndep)
    {
        if(ndep>=maxdep)
        {
            memcpy(on_road,on_road_tmp,sizeof(on_road));
            maxdep=ndep;
        }
    
        rep(i,0,int(G[now].size())-1)
            if(dep[G[now][i]]==-1)
            {
                dep[G[now][i]]=dep[now]+1;
                on_road_tmp[G[now][i]]=true;
                dfs2(G[now][i],ndep+1);
                on_road_tmp[G[now][i]]=false;
            }
    }
    
    int
    main()
    {
        int kase=0;
        while(cin>>n)
        {
            if(!n) break;
            rep(i,1,n) G[i].clear();
            rep(i,1,n) pa[i]=i;
            int e; cin>>e;
            bool has_loop=false;
            rep(i,1,e)
            {
                int u,v; cin>>u>>v;
                G[u].PB(v);
                G[v].PB(u);
                if(find_pa(u)!=find_pa(v)) union_pa(u,v);
                else has_loop=true;
            }
            if(e>n-1) has_loop=true;
            bool ok=true;
            if(has_loop || !judge_cnt())
                ok=false;
            if(ok)
            {
                MS(dep,-1);
                dep[1]=0;
                dfs(1);
                int pnt_id=1;
                maxdep=0;
                rep(i,1,n) if(dep[pnt_id]<dep[i])
                {
                    pnt_id=i;
                    maxdep=dep[pnt_id];
                }
                ZERO(on_road_tmp);
                MS(dep,-1);
                dep[pnt_id]=0;
                on_road_tmp[pnt_id]=true;
                dfs2(pnt_id, 0);
                rep(i,1,n)
                    if(!on_road[i]&&G[i].size()!=1)
                    {
                        ok=false; break;
                    }
            }
            if(ok) cout<<"Graph "<<++kase<<" is a caterpillar."<<endl;
            else cout<<"Graph "<<++kase<<" is not a caterpillar."<<endl;
        }
        return 0;
    }
    
    如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
  • 相关阅读:
    腾讯的网站是如何检测到你的 QQ 已经登录?
    怎么改变html中placeholderr的文字颜色
    [分享]2013:Linux的黄金之年-十大杰出成就
    .NET MVC 两种视图引擎(Razor、Aspx)
    android:visibility
    获取目录
    Android 判断字符串是否相等
    Android Sqlite
    android 积累
    Android ListView 使用
  • 原文地址:https://www.cnblogs.com/samhx/p/POJ-3310.html
Copyright © 2011-2022 走看看