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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【POJ - 2762】Going from u to v or from v to u?(Tarjan缩点,树形dp 或 拓扑排序,欧拉图相关)

發(fā)布時間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【POJ - 2762】Going from u to v or from v to u?(Tarjan缩点,树形dp 或 拓扑排序,欧拉图相关) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題干:

In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn't know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?

Input

The first line contains a single integer T, the number of test cases. And followed T cases.?

The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.?

Output

The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.

Sample Input

1 3 3 1 2 2 3 3 1

Sample Output

Yes

題目大意:

問一個圖是否是單連通的。

解題報告:

先對全圖求一次SCC,可以知道每個SCC內(nèi)的點都是單連通的,那么把每個SCC縮點構(gòu)建出DAG之后再判斷這個DAG是否單連通即可。方法不唯一:可以是拓撲排序,看他每次是否只有一個活躍點就可以了,如果不是一個,那肯定不符合要求。

第二種方法:是DAG動規(guī)找出最長鏈,如果最長鏈上的點個數(shù)等于SCC個數(shù),那么DAG單連通。(因為如果最長鏈都不能覆蓋所有點,那么必定有兩個點之間是無法到達的)

?

剛開始以為直接判斷是否是一條鏈就行了,后來3 -> 1、?1 -> 2、3?-> 2這組數(shù)據(jù)就Hack掉了,,本應(yīng)該是Yes,但是這樣肯定就是No了。然后想判一個歐拉通路,雖然可以AC,但是有數(shù)據(jù)是過不了的。(數(shù)據(jù)水了)

AC代碼:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 1000 + 5; struct Edge {int fr,to,ne; } e[6005],E[6005]; vector<int> vv[MAX]; int head[MAX],HEAD[MAX],tot,TOT; bool ok[MAX][MAX]; void add(int u,int v) {e[++tot].to = v;e[tot].fr = u;e[tot].ne = head[u];head[u] = tot; } int n,m; int DFN[MAX],LOW[MAX],scc,clk,index,sk[MAX],vis[MAX],col[MAX],in[MAX],out[MAX]; void Tarjan(int x) {DFN[x] = LOW[x] = ++clk;vis[x]=1;sk[++index] = x;for(int i = head[x]; ~i; i = e[i].ne) {int v = e[i].to;if(DFN[v] == 0) {Tarjan(v);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]) {LOW[x] = min(LOW[x],DFN[v]);} }if(LOW[x] == DFN[x]) {scc++;while(1) {int tmp = sk[index];index--;vis[tmp]=0;col[tmp] = scc;if(tmp == x) break;} } } void init() {scc=clk=tot=TOT=index=0;for(int i = 1; i<=n; i++) {vv[i].clear();head[i] = HEAD[i] = -1;vis[i] = DFN[i] = LOW[i] = in[i] = out[i] = 0;}for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) ok[i][j]=0;} } bool topu() {queue<int> q;for(int i = 1; i<=scc; i++) {if(in[i] == 0) q.push(i);}int cnt = 0;while(!q.empty()) {if(q.size() > 1) return 0 ;int cur = q.front();q.pop();cnt++;int up = vv[cur].size();for(int i = 0; i<up; i++) {int v = vv[cur][i];in[v]--;if(in[v] == 0) q.push(v);} }return cnt == scc; } int main() {int t;cin>>t;while(t--) {scanf("%d%d",&n,&m); init();for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b);}for(int i = 1; i<=n; i++) {if(DFN[i] == 0) Tarjan(i);}for(int a,b,i = 1; i<=tot; i++) {a=col[e[i].fr],b=col[e[i].to];if(a==b) continue;if(ok[a][b]) continue;ok[a][b]=1;in[b]++;out[a]++;vv[a].pb(b);}bool flag = topu();if(flag) puts("Yes");else puts("No");}return 0 ; }

AC代碼:(樹形dp)

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 1000 + 5; struct Edge {int fr,to,ne; } e[6005],E[6005]; vector<int> vv[MAX]; int head[MAX],HEAD[MAX],tot,TOT; bool ok[MAX][MAX]; void add(int u,int v) {e[++tot].to = v;e[tot].fr = u;e[tot].ne = head[u];head[u] = tot; } int n,m; int dp[MAX]; int DFN[MAX],LOW[MAX],scc,clk,index,sk[MAX],vis[MAX],col[MAX],in[MAX],out[MAX]; void Tarjan(int x) {DFN[x] = LOW[x] = ++clk;vis[x]=1;sk[++index] = x;for(int i = head[x]; ~i; i = e[i].ne) {int v = e[i].to;if(DFN[v] == 0) {Tarjan(v);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]) {LOW[x] = min(LOW[x],DFN[v]);} }if(LOW[x] == DFN[x]) {scc++;while(1) {int tmp = sk[index];index--;vis[tmp]=0;col[tmp] = scc;if(tmp == x) break;} } } void init() {scc=clk=tot=TOT=index=0;for(int i = 1; i<=n; i++) {vv[i].clear();head[i] = HEAD[i] = -1;vis[i] = DFN[i] = LOW[i] = in[i] = out[i] = dp[i] = 0;}for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) ok[i][j]=0;} } int dfs(int cur){if(dp[cur])return dp[cur];int num=0;int up = vv[cur].size();for(int i = 0; i<up; i++) {int v = vv[cur][i];num=max(num,dfs(v));}return dp[cur]=num+1; } int main() {int t;cin>>t;while(t--) {scanf("%d%d",&n,&m); init();for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b);}for(int i = 1; i<=n; i++) {if(DFN[i] == 0) Tarjan(i);}for(int a,b,i = 1; i<=tot; i++) {a=col[e[i].fr],b=col[e[i].to];if(a==b) continue;if(ok[a][b]) continue;ok[a][b]=1;in[b]++;out[a]++;vv[a].pb(b);}int flag = 0;for(int i = 1; i<=n; i++){if(dfs(LOW[i]) == scc){flag=true;break;}//或者dfs(i)也可以ac}if(flag) puts("Yes");else puts("No");}return 0 ; }

這里送上一種雖然錯誤但是可以AC的代碼,引以為戒。

AC代碼:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 1000 + 5; struct Edge {int fr,to,ne; } e[6005],E[6005]; int f[MAX]; int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]); } void merge(int u,int v) {int t1 = getf(u),t2 = getf(v);f[t2] = t1; } int head[MAX],HEAD[MAX],tot,TOT; bool ok[MAX][MAX]; void add(int u,int v) {e[++tot].to = v;e[tot].fr = u;e[tot].ne = head[u];head[u] = tot; } int n,m; int DFN[MAX],LOW[MAX],scc,clk,index,sk[MAX],vis[MAX],col[MAX],in[MAX],out[MAX]; void Tarjan(int x) {DFN[x] = LOW[x] = ++clk;vis[x]=1;sk[++index] = x;for(int i = head[x]; ~i; i = e[i].ne) {int v = e[i].to;if(DFN[v] == 0) {Tarjan(v);LOW[x] = min(LOW[x],LOW[v]);}else if(vis[v]) {LOW[x] = min(LOW[x],DFN[v]);} }if(LOW[x] == DFN[x]) {scc++;while(1) {int tmp = sk[index];index--;vis[tmp]=0;col[tmp] = scc;if(tmp == x) break;} } } void init() {scc=clk=tot=TOT=index=0;for(int i = 1; i<=n; i++) {head[i] = HEAD[i] = -1;f[i]=i;vis[i] = DFN[i] = LOW[i] = in[i] = out[i] = 0;}for(int i = 1; i<=n; i++) {for(int j = 1; j<=n; j++) ok[i][j]=0;} } int main() {int t;cin>>t;while(t--) {scanf("%d%d",&n,&m); init();for(int a,b,i = 1; i<=m; i++) {scanf("%d%d",&a,&b);add(a,b);}for(int i = 1; i<=n; i++) {if(DFN[i] == 0) Tarjan(i);}for(int a,b,i = 1; i<=tot; i++) {a=col[e[i].fr],b=col[e[i].to];if(a==b) continue;if(ok[a][b]) continue;ok[a][b]=1;merge(a,b);in[b]++;out[a]++;}int ans = 0;int flag = 0,ru=0,chu=0;for(int i = 1; i<=scc; i++) {if(f[i] == i) ans++;if(in[i]==out[i]) continue;if(in[i]-out[i]==1) ru++;else if(out[i]-in[i]==1) chu++;else {flag=1; break;}} if(ans > 1 || flag == 1 || ru!=chu || ru>1 || chu>1 ) puts("No");else puts("Yes");}return 0 ; }

但是其實這樣是不對的:

1
3 3
3 1
1 2
3 2

這組樣例就過不了,所以不能簡單判斷一個有向圖歐拉通路。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的【POJ - 2762】Going from u to v or from v to u?(Tarjan缩点,树形dp 或 拓扑排序,欧拉图相关)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。