1. 程式人生 > >「日常學習」Caterpillar(POJ-3310)

「日常學習」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;
}