Div1 小A抓小B tarjan双连通分量缩点+dfs
生活随笔
收集整理的這篇文章主要介紹了
Div1 小A抓小B tarjan双连通分量缩点+dfs
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述
小A和小B在一個無向圖G上進行一個游戲。圖G是連通的,有n個點,n條邊,無重邊,無自環,結點編號為1~n。游戲開始前小A在結點x,小B在結點y(x≠y)。游戲開始后,小A和小B輪流進行移動(小A先移動),每次移動可以從當前結點移動到與當前結點相鄰的某個結點。小A的目標是抓到小B(某一次移動之后小A與小B在同一個結點),小B的目標是不被小A抓到。兩人都有圖G的地圖,并且知道對方在哪個結點,兩人都采取最優策略,問小A是否能通過有限次移動抓到小B。
輸入描述
第1行3個整數n、x、y
第2~n+1行每行2個整數u、v,代表u與v之間有邊相連。
輸出描述
若小A能通過有限次移動抓到小B,輸出1,否則輸出0。
數據范圍
n≤100000
樣例輸入
10 2 4 1 2 1 3 2 4 1 5 5 6 1 7 5 8 6 9 3 10 8 10樣例輸出
1題解,這是一個樹,并且這個樹上存在且存在一個環。
1.當A和B之間距離為1或0的時候,直接輸出1。
2.否則的話,當環的長度小于等于3的時候,直接輸出1,因為B一定會被A捉到。
3.我們進行雙連通分量的縮點,將環縮成一個點,下面我們判斷,當A、B同屬于一個環上的時候,直接輸出0,因為B繞著環跑永遠不會被捉到。
4.然后我們從環縮成的點開始進行dfs序遍歷,得到每一個點到基環的距離,如果dis[belong[x]] + 1 <= dis[belong[y]]表明A距離基環更近,直接輸出1,否則輸出0.
代碼:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5+10; int head[MAXN]; int cnt; struct edge{ int v; int next; int cost; }Es[MAXN<<1]; void init(){ cnt = 0; memset(head,-1,sizeof(head)); } inline void add_edge(int i,int j,int cost){ Es[cnt].v = j; Es[cnt].cost = cost; Es[cnt].next = head[i]; head[i] = cnt++; } int n,x,y; int DFN[MAXN],LOW[MAXN]; int stk[MAXN],vis[MAXN],belong[MAXN]; int idx,sccnum,tot; vector<int> scc[MAXN]; void tarjan(int x,int fa){DFN[x] = LOW[x] = ++ tot;stk[++idx] = x;vis[x] = 1;for(int e = head[x];e != -1;e = Es[e].next){int v = Es[e].v;if(v == fa) continue;if(!DFN[v]){tarjan(v,x);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]){LOW[x] = min(LOW[x],DFN[v]);}}if(DFN[x] == LOW[x]){++sccnum;int item;do{item = stk[idx--];belong[item] = sccnum;scc[sccnum].push_back(item);vis[item] = 0;}while(x != item);} } int dis[MAXN]; int vis2[MAXN]; void dfs(int x,int dep){dis[x] = dep;for(int i = 0;i < scc[x].size();++i){int u = scc[x][i];for(int e = head[u];e != -1;e = Es[e].next){int v = Es[e].v;if(!vis2[belong[v]]){vis2[belong[v]] = 1;dfs(belong[v],dep+1);}}} } int main(){init();scanf("%d%d%d",&n,&x,&y);if(x == y) {puts("1");return 0;}for(int i = 0;i < n;i++){int a,b;scanf("%d%d",&a,&b);add_edge(a,b,1);add_edge(b,a,1);}for(int e = head[x];e != -1;e = Es[e].next){int v = Es[e].v;if(v == y){puts("1");return 0;}}tarjan(1,0);int start = 0;for(int i = 1;i <= sccnum;i++){if(scc[i].size() > 3){start = i;}}if(!start){puts("1");return 0;}if(belong[x] == belong[y]){puts("0");return 0;}dfs(start,0);if(dis[belong[x]] + 1 <= dis[belong[y]]){puts("1");}else{puts("0");}return 0; } /* 7 4 1 1 2 2 3 3 4 4 5 5 6 6 7 7 4 */總結
以上是生活随笔為你收集整理的Div1 小A抓小B tarjan双连通分量缩点+dfs的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Summer Training day6
- 下一篇: Codeforces Gym 10117