「日常學習」Caterpillar(POJ-3310)
阿新 • • 發佈:2018-11-05
題意與分析
一條很有趣的題目。給一個無向圖,問它是否無環,且可以在上面找到一條線,使所有的頂點要麼在線上要麼不在線上但在與線相連的邊上。
那麼首先要確定所有點聯絡在一起。這個可以同判環一起處理:如果建圖新加入的點同原先的點含有同一個祖先,那它肯定是環沒跑了。然後遍歷所有節點,看看是否擁有同一個祖先。這樣就完成了兩個任務。
接下來需要一點分析:我們可以證明,這條線(如果存在)一定是樹的直徑,或者是與樹的直徑長度相等(在端點差一個點那邊分的叉)。為什麼?如果這條線小於樹的直徑,那麼樹的直徑與它的交點一定會延伸出兩個點,那麼這就一定會翻車,這條線一定不會滿足條件。所以如果有一條線滿足這個條件,那它必須得是樹的直徑。然後就是之前知識學習的地方,先找樹的直徑(這裡需要記錄端點,我沒有采用棧的方法記錄,採用了一種比較簡單的方法解決),然後判斷非樹直徑的點是否度數為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; }