The 2020 ICPC Asia Taipei-Hsinchu Site Programming Contest I題Critical Structures
阿新 • • 發佈:2021-10-22
你將不再是道具,而是成為人如其名的人#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; #define mp make_pair #define newline puts("") const int maxn = 1010; int n,m; vector<int> G[maxn]; int dfn[maxn],low[maxn],cnt = 0; stack<int> st; int ct = 0;//聯通分量的數量 // int book[maxn],num[maxn];//每個點所在環的編號以及每個環上點的數量 vector<int> cir[maxn];//cir[k]表示第k個環上的點是哪些 bool is_cut[maxn];//是否是割點 int fa[maxn]; map<pii,bool> is_bridge; int par[maxn],siz[maxn]; int ans1,ans2,ans3,ans4; int getpa(int x){ return x == par[x] ? x : par[x] = getpa(par[x]); } int gcd(int a,int b){ return !b ? a : gcd(b,a%b); } void tarjan(int u,int f)//第二個引數主要是傳父親 { dfn[u] = low[u] = ++cnt; st.push(u); fa[u] = f; int rt_num = 0; for (auto v : G[u]) { if(!dfn[v]){ tarjan(v,u); rt_num ++; low[u] = min(low[u],low[v]); if((rt_num >= 2 && fa[u] == 0) || (fa[u]!=0 && low[v] >= dfn[u])) is_cut[u] = true; if(low[v] > dfn[u]) {//u,v這條邊是橋 is_bridge[mp(min(u,v),max(u,v))] = true; ans2++; } } else if(v != fa[u]) { low[u] = min(low[u],dfn[v]); } } if(dfn[u] == low[u]) { ++ct; while(1) { int x = st.top(); st.pop(); cir[ct].push_back(x); if(x == u) break; } } } void Clear() { ans1 = ans2 = ans3 = 0; ans4 = 1; for (int i=1;i<=ct;i++) cir[i].clear(); cnt = ct = 0; for (int i=1;i<=n;i++){ G[i].clear(); fa[i] = 0; is_cut[i] = false; par[i] = 0; siz[i] = 0; dfn[i] = low[i] = 0; } while(!st.empty()) st.pop(); is_bridge.clear(); } void solve() { scanf("%d%d", &n, &m); for (int i=1;i<=m;i++) { int u,v; scanf("%d%d", &u,&v); G[u].push_back(v),G[v].push_back(u); } tarjan(1,0); // for (int i=1;i<=n;i++) // { // cout<<"i = "<<i<<" dfn = "<<dfn[i]<<" low = "<<low[i]<<endl; // } // for (int i=1;i<=n;i++) cout<<"i = "<<i<<" is_cut = "<<is_cut[i]<<endl; for (int i=1;i<=n;i++) ans1 += (int)is_cut[i];//割點數量要在外面加 ans3 += ans2; for (int i=1;i<=n;i++) par[i] = i,siz[i] = 0; for (int u=1;u<=n;u++) { for (auto v : G[u]) { if(v < u) continue; if(is_bridge[mp(u,v)]) continue; int f1 = getpa(u),f2 = getpa(v); if(f1 > f2) swap(f1,f2); if(f1 != f2) { par[f2] = f1; siz[f1] += siz[f2] + 1; } else siz[f1]++; } } for (int i=1;i<=n;i++) { int fi = getpa(i); if(i == fi && siz[fi] > 0) ans3++; ans4 = max(ans4,siz[fi]); } // cout<<"ans3 = "<<ans3<<" ans4 = "<<ans4<<endl; int g = gcd(ans3,ans4); printf("%d %d %d %d\n",ans1,ans2,ans3/g,ans4/g); Clear(); } int main() { // freopen("1.in","r",stdin); // freopen("1.out","w",stdout); int T; scanf("%d",&T); for(int _=1;_<=T;_++) { solve(); } return 0; }