【洛谷】P7687 [CEOI2005] Critical Network Lines (tarjan)
阿新 • • 發佈:2022-03-14
連結
P7687 [CEOI2005] Critical Network Lines
分析
1 由本題對關鍵路徑的定義,首先能想到它首先是滿足割邊(橋)的定義的。
因此我們可以先找出所有的橋,答案是這個集合的一個子集。
2 進一步地,如果當前這條是橋的邊滿足:它所連線的的兩側 至少有一側沒有兩種種類的點,那麼如果我們去掉這條邊,兩側就不再相連通,缺少點的種類的那一側無法訪問缺的這種種類的點,於是把它加進答案。
依據此思路可以先寫tarjan找出所有的橋,再寫一個dfs函式統計當前位置下兩種點的個數,一邊判斷。
然而會超時(tle \(\times\) 1)
優化
判斷的時候需要在原集合中進行查詢。我們於是要對這個查詢進行優化。
仔細觀察(對於無向連通圖的)tarjan和dfs函式,它們的結構驚人的相似,因此我們可以就寫一個tarjan函式,邊統計邊判斷當前的橋是否滿足題目要求
code
#include<bits/stdc++.h> //luogu p7687 先找到所有的橋,再判斷 橋的兩邊是否只有<=1種 若是才留下 #define ll long long using namespace std; const int N = 100005; int n,m,A,B; int a[N],b[N]; bool aa[N],bb[N]; vector<int>g[N],v[N]; bool in[N],vis[N]; int cnt,t,e; int x[10*N],y[10*N]; int rd[N],cd[N]; int dfn[N],low[N],sta[N],f[N]; vector<pair<int,int>>ans,final; int dp[N][2]; //0:none 1:A 2:B 3:A+B void tarjan(int now,int fa){ //無向圖 dfn[now]=low[now]=++cnt; dp[now][0]+=aa[now];// dp[now][1]+=bb[now];// for(int i=0;i<g[now].size();i++){ int x=g[now][i]; if(!dfn[x]){ tarjan(x,now); dp[now][0]+=dp[x][0];// dp[now][1]+=dp[x][1];// low[now]=min(low[now],low[x]); if(low[x]>dfn[now]){ if(dp[x][0]==A||dp[x][0]==0||dp[x][1]==B||dp[x][1]==0){ ans.push_back(make_pair(x,now)); } } } else{ if(fa!=x){ low[now]=min(low[now],dfn[x]); } } } } int main(){ scanf("%d%d%d%d",&n,&m,&A,&B); for(int i=1;i<=A;i++) scanf("%d",&a[i]),aa[a[i]]=1; for(int i=1;i<=B;i++) scanf("%d",&b[i]),bb[b[i]]=1; for(int i=1;i<=m;i++){ scanf("%d%d",&x[i],&y[i]); g[x[i]].push_back(y[i]); g[y[i]].push_back(x[i]); } for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(i,i); } } dfs(1,1); printf("%d\n",ans.size()); for(auto i:ans){ printf("%d %d\n",i.first,i.second); } return 0; }