日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Div1 小A抓小B tarjan双连通分量缩点+dfs

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Div1 小A抓小B tarjan双连通分量缩点+dfs 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

A和小B在一個無向圖G上進行一個游戲。圖G是連通的,有n個點,n條邊,無重邊,無自環,結點編號為1~n。游戲開始前小A在結點x,小B在結點yxy)。游戲開始后,小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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。