中午又水了一发
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730
想一想,如果删除的点恰好是割点,那么就需要在割点两边各找一个安全通道,但是如果将图中所有割点删去后,发现一个联通块有两个或以上个割点,那么这个块内不需要建通道,因为一个割点删去后,人可以从别的路到其他联通块。
所以删去割点后,枚举所有只与一个割点相连的块,利用将其中点数相乘即可。
如果没有割点,那么要修两个通道,(n-1)*n/2种方案。
代码凌乱:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int n,m; int v[1501]={},pr[1501]={},num,bia[1501]={}; bool cut[1501]={},vis[1501]={}; inline void add(int l,int r) { v[num]=r; pr[num]=bia[l];bia[l]=num; num++; v[num]=l; pr[num]=bia[r];bia[r]=num; num++; } int low[1501]={},dfn[1501]={},clo=0; int son[1501]={}; void tarjan (int u,int fa) { low[u]=dfn[u]=++clo; int i,r;son[u]=0; for (i=bia[u];i!=-1;i=pr[i]) { r=v[i]; if (!dfn[r]) { tarjan(r,u);son[u]++; if (low[r]<low[u]) low[u]=low[r]; if (dfn[u]<=low[r]&&fa!=-1) cut[u]=true; } else if (dfn[r]<dfn[u]&&low[u]>low[r]) low[u]=low[r]; } if (son[u]>1&&fa==-1) cut[u]=true; } int lia[1501]={},color,nco[1501]={}; int mar[1501]={}; void dfs(int u) { vis[u]=true; int i,r;nco[color]++; for (i=bia[u];i!=-1;i=pr[i]) { r=v[i]; if (vis[r]) continue; if (!cut[r]) dfs(r); else { if (mar[r]!=color) mar[r]=color,lia[color]++; } } } inline void init() { memset(bia,-1,sizeof(bia)); memset(nco,0,sizeof(nco)); memset(mar,0,sizeof(mar)); memset(lia,0,sizeof(lia)); memset(cut,false,sizeof(cut)); memset(vis,false,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); num=color=clo=n=0; } int main() { int i,j,l,r,xxx=0; while (1) { init(); scanf("%d",&m); if (m==0) break;xxx++; for (i=1;i<=m;i++) { scanf("%d%d",&l,&r); if (l==-1) break; add(l,r); n=max(l,n);n=max(r,n); } for (i=1;i<=n;i++) { if (!dfn[i]) tarjan(i,-1); } int ans=0; long long hee=1ll; for (i=1;i<=n;i++) { if (!cut[i]&&!vis[i]) { color++;dfs(i); if (lia[color]==1) ans++,hee*=nco[color]; } } if (color==1) ans=2,hee=n*(n-1)/2; cout<<"Case "<<xxx<<": "<<ans<<" "<<hee<<endl; } return 0; }