题意:有一座地下的稀有金属矿由n条隧道和一些连接点组成,其中每条隧道连接两个连接点。任意两个连接点之间最多只有一条隧道。为了降低矿工的危险,你的任务是在一些连接点处安装太平井和相应的逃生装置,使得不管哪个连接点倒塌,不在此连接点的所有矿工都能到达太平井逃生(假定除了倒塌的连接点外,其他隧道和连接点完好无损)。为了节约成本,你应当在尽量少的连接点安装太平井。还要需要计算出太平井的数目最小时的安装方案总数。
分析:本题的模型是:在一个无向图上选择尽量少的点涂黑(对应太平井),使得任意删除一个点后,每个连通分量至少有一个黑点。不难发现,把割顶涂黑是不划算的。进一步分析,当一个点-双连通分量只有一个割顶时才需要涂,而且是任选一个非割顶涂黑即可。两个问题同时解决。
一个特殊情况是整个图没有割顶。此时需要涂两个点,方案总数是V*(V-1)/2,其中V是连接点的个数。
代码:
#include#include #include #include #include #include #include #include #include using namespace std; const int maxn =50000+10; int n,m; int pre[maxn],iscut[maxn],dfs_clock,bcc_cnt,bccno[maxn]; vector G[maxn],bcc[maxn]; void init() { dfs_clock=bcc_cnt=0; memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); memset(bccno,0,sizeof(bccno)); for(int i=1; i S; int dfs(int u,int fa) { int lowu = pre[u] =++dfs_clock; int child =0; for(int i=0; i = pre[u]) { iscut[u]=1; bcc_cnt++; bcc[bcc_cnt].clear(); for(; ;) { Edge x=S.top(); S.pop(); if(bccno[x.u]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; } if(bccno[x.v]!=bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u&&x.v==v) break; } } } else if(pre[v]