题意:
一些隧道组成矿井 现在要修建尽量少的逃生通道 使得无论哪里发生事故 所有人均能逃出 求方案数
思路:
这道题比较容易联想到割点 因为只有这种点出事矿井才会不连通 那么首先就找出所有割点
分析最少要建几个逃生通道 那当然是每个连通块各一个 因此需要把求出连通块顶点数之积
最后考虑特殊情况 没有割点 那么随便两个地方建就好了 不能建一个 万一就那里出事了呢…
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; #define N 50010 typedef long long LL; int m,n,tot,t,ans1,res,idx; int head[N],dfn[N],low[N],cut[N],vis[N]; struct edge { int v,flag,next; }ed[N*2]; LL ans2; set<int> next; void add(int u,int v) { ed[tot].v=v; ed[tot].flag=0; ed[tot].next=head[u]; head[u]=tot++; } void tarjan(int u,int fa) { int i,v,son=0; dfn[u]=low[u]=++idx; for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(ed[i].flag||dfn[v]>=dfn[u]) continue; ed[i].flag=ed[i^1].flag=1; if(dfn[v]==-1) { son++; tarjan(v,u); low[u]=min(low[u],low[v]); if(u!=fa&&dfn[u]<=low[v]) cut[u]=1; } else low[u]=min(low[u],dfn[v]); } if(u==fa&&son>1) cut[u]=1; } void dfs(int u) { int i,v; res++; vis[u]=1; for(i=head[u];~i;i=ed[i].next) { v=ed[i].v; if(cut[v]) next.insert(v); if(!cut[v]&&!vis[v]) dfs(v); } } int main() { int i,u,v; while(~scanf("%d",&m)) { if(!m) break; tot=n=idx=0; memset(head,-1,sizeof(head)); memset(dfn,-1,sizeof(dfn)); memset(cut,0,sizeof(cut)); memset(vis,0,sizeof(vis)); for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); n=max(n,u); n=max(n,v); add(u,v); add(v,u); } tarjan(1,1); ans1=0; ans2=1; for(i=1;i<=n;i++) { if(!cut[i]&&!vis[i]) { res=0; next.clear(); dfs(i); if(next.size()==1) { ans1++; ans2*=res; } } } if(ans1==0) { ans1=2; ans2=(LL)(n)*(n-1)/2; } printf("Case %d: ",++t); printf("%d %lld\n",ans1,ans2); } return 0; }
UVALive 5135 Mining Your Own Business
原文地址:http://blog.csdn.net/houserabbit/article/details/38929653