HDU 3639 強連通加縮點
阿新 • • 發佈:2019-01-02
///先瞎做一番試試,我的實力的確是應該好好漲漲了。 //總算過了。。。 #include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<string> #define inf 0x3f3f3f3f #define maxn 100500 using namespace std; int n;//n m 為點數和邊數 int sum; int head[maxn], edgenum; int minw[maxn]; int DFN[maxn], Low[maxn], Stack[maxn], top, Time; //Low[u]是點集{u點及以u點為根的子樹} 中(所有反向弧)能指向的(離根最近的祖先v) 的DFN[v]值(即v點時間戳) int taj;//連通分支標號,從1開始 int Belong[maxn];//Belong[i] 表示i點屬於的連通分支 bool Instack[maxn]; vector<int> bcc[maxn]; //標號從1開始 bool vis[maxn]; vector<int>G[maxn]; int du[maxn]; int gu[maxn]; struct Edge { int from, to, nex; bool sign;//是否為橋 }edge[60000]; void addedge(int u, int v) {//邊的起點和終點 Edge E={u, v, head[u], false}; edge[edgenum] = E; head[u] = edgenum++; } void tarjan(int u ,int fa)//求出圖的強聯通分量 { DFN[u] = Low[u] = ++ Time ; Stack[top ++ ] = u ; Instack[u] = 1 ; for (int i = head[u] ; ~i ; i = edge[i].nex ) { int v = edge[i].to ; if(DFN[v] == -1) { tarjan(v , u) ; Low[u] = min(Low[u] ,Low[v]) ; if(DFN[u] < Low[v]) { edge[i].sign = 1;//為割橋 } } else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ; } if(Low[u] == DFN[u]) { int now; taj ++ ; bcc[taj].clear(); do { now = Stack[-- top] ; Instack[now] = 0 ; Belong [now] = taj ; bcc[taj].push_back(now); }while(now != u) ; } } void tarjan_init(int all) { memset(DFN, -1, sizeof(DFN)); memset(Instack, 0, sizeof(Instack)); top = Time = taj = 0; for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意開始點標!!! } void suodian()////還要更新出入度。。 { memset(du, 0, sizeof(du)); memset(gu,0,sizeof(gu)); memset(minw,0,sizeof(minw)); for(int i = 1; i <= taj; i++)G[i].clear(); for(int i = 0; i < edgenum; i++) { int u = Belong[edge[i].from], v = Belong[edge[i].to]; if(u!=v)G[v].push_back(u), du[u]++,gu[v]++;///g[u]存的是出度,du[v]存的是入度 } for(int i=1;i<=n;i++) minw[Belong[i]]++; } void init(){memset(head, -1, sizeof(head)); edgenum=0;} ///遍歷圖、、建反向圖然後深搜。。 void dfs(int u)///入度為0的點。。 { vis[u]=true; sum+=minw[u]; for(int i=0;i<G[u].size();i++) { if(!vis[G[u][i]]) dfs(G[u][i]); } //反向建圖是因為要找的是可到達該點的強連同分量。。 } int allans[maxn]; int TOT[maxn]; void solve() { memset(allans,0,sizeof(allans)); int maxx=0;int index=0; for(int i=1;i<=taj;i++) { if(du[i]==0) { memset(vis,false,sizeof(vis)); sum=0; dfs(i); allans[i]=sum; if(allans[i]>maxx) { index=i; maxx=allans[i]; } } } cout<<maxx-1<<endl; int tot=0; // cout<<taj<<" taj"<<endl; // for(int i=1;i<=n;i++) // cout<<Belong[i]<<endl; // cout<<"測試。。。"<<endl; // cout<<index<<endl; // for(int i=1;i<=n;i++) // if(Belong[i]==index) // cout<<i<<" "; // cout<<endl; // cout<<"-----------------------------"<<endl; for(int i=1;i<=n;i++) { if(allans[Belong[i]]==maxx) TOT[++tot]=i; } for(int i=1;i<tot;i++) cout<<TOT[i]-1<<" "; cout<<TOT[tot]-1<<endl; } int main() { // freopen("inn.txt","r",stdin); int cas,a,b; scanf("%d",&cas); int ca=0; while(cas--) { ca++; init(); int m; scanf("%d%d",&n,&m); while(m--) { scanf("%d%d",&a,&b); a++,b++; addedge(a,b); } tarjan_init(n); suodian(); cout<<"Case "<<ca<<": "; solve(); } }