1 solutions
-
0
难度: 紫(My 8th purple.)
算法: (点)双连通分量
先跑一遍 Tarjan 求出割点,再通过 dfs 求点双连通分量。(不等同于洛谷的模板)
如果一个点的数量为 的点双连通分量:
没有割点与之相连。不难得到这个点双中需要开两个窗口,方案数为 。
有一个割点与之相连。这个强连通分量内需要开一个窗口,否则割点断了就跑不出去了。方案数为 。
有两个割点与之相连。这个强连通分量内啥也不用干,因为即使一个割点断了也可以通过另一个跑掉。
最后将开的窗口数累加,方案数累乘即可。
记得清空。
#include<bits/stdc++.h> using namespace std; unsigned long long num,ans=1; int m,n,a,b,r,f,v,nk,nc; int l[505],d[505],ct[505],vis[505],w[505],c,t; vector<int> e[505],k[505]; void tarj(int u){ d[u]=l[u]=++c; int son=0; for(int i=0;i<int(e[u].size());i++){ int v=e[u][i]; if(!d[v]){ son++; tarj(v); l[u]=min(l[u],l[v]); if(l[v]>=d[u]&&u!=r) ct[u]=1; } else l[u]=min(l[u],d[v]); } if(son>=2&&u==r) ct[u]=1; } void dfs(int u){ vis[u]=t; nk++; for(int i=0;i<int(e[u].size());i++){ int v=e[u][i]; if(ct[v]&&vis[v]!=t){ nc++; vis[v]=t; } else if(!vis[v]) dfs(v); } } int main(){ while(1){ scanf("%d",&m); if(m==0) return 0; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); n=max(n,max(a,b)); } for(int i=1;i<=n;i++){ if(!d[i]){ r=i; tarj(i); } } for(int i=1;i<=n;i++){ if(!ct[i]&&!vis[i]){ t++; nk=nc=0; dfs(i); if(nc==0){ if(nk==1) num++; else num+=2,ans*=nk*(nk-1)/2; } if(nc==1){ num++,ans*=nk; } } } printf("Case %d: %llu %llu\n",++v,num,ans); for(int i=1;i<=n;i++){ e[i].clear(),k[i].clear(); l[i]=d[i]=vis[i]=ct[i]=0; } n=0,c=0,t=0,num=0,ans=1; } }
- 1
Information
- ID
- 101
- Time
- 1000ms
- Memory
- 128MiB
- Difficulty
- 10
- Tags
- # Submissions
- 7
- Accepted
- 3
- Uploaded By