首页 > 代码库 > 【bzoj2730】 HNOI2012—矿场搭建
【bzoj2730】 HNOI2012—矿场搭建
http://www.lydsy.com/JudgeOnline/problem.php?id=2730 (题目链接)
题意
给出一张图,问如果删掉其中一个点,使得其他每个节点都有一个安全撤离的出口,最少需要设立多少个出口,有多少种方案。
Solution
很明显,一张图至少要设立2个出口(一个点双连通分量),如果删掉不是割点的点,对答案不会有什么限制,考虑删掉的点是割点。
我们对割点以外的联通快进行染色,每一种颜色就表示在这些同样的颜色中的节点至少要设置一个出口,若一个节点被染成了多种颜色,那么表明在此处设立出口不是最优的。
细节
十个Tarjan五个错。。注意判断割点的条件,当判断搜索树根是不是割点时,有点小麻烦。
代码
// bzoj2730#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#define LL long long#define inf 2147483640#define Pi acos(-1.0)#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);using namespace std;const int maxn=1010;struct edge {int to,next;}e[maxn<<1];int low[maxn],dfn[maxn],head[maxn],cut[maxn],vis[maxn],id[maxn],sum[maxn];int cnt,ind,m,n;void Init() { cnt=ind=n=0; memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); memset(cut,0,sizeof(cut)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(sum,0,sizeof(sum)); memset(id,0,sizeof(id));}void link(int u,int v) { e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt; e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;}void Tarjan(int x,int fa,int rt) { int tot=0; dfn[x]=low[x]=++ind; for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) { if (!dfn[e[i].to]) { Tarjan(e[i].to,x,rt); low[x]=min(low[x],low[e[i].to]); if (low[e[i].to]>=dfn[x] && x!=rt) cut[x]=1; //important else if (x==rt) tot++; } else low[x]=min(low[x],dfn[e[i].to]); } if (tot>1) cut[x]=1; //important}void dfs(int x,int col) { vis[x]=cnt; if (!id[x]) id[x]=col; else id[x]=-1; for (int i=head[x];i;i=e[i].next) if (vis[e[i].to]!=cnt && !cut[e[i].to]) dfs(e[i].to,col);}int main() { int T=0; while (1) { scanf("%d",&m); if (m==0) break; printf("Case %d: ",++T); Init(); for (int u,v,i=1;i<=m;i++) { scanf("%d%d",&u,&v); link(u,v);n=max(n,max(u,v)); } for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0,i); cnt=0;int col=0; for (int i=1;i<=n;i++) if (cut[i]) { cnt++; for (int j=head[i];j;j=e[j].next) if (vis[e[j].to]!=cnt && !cut[e[j].to]) dfs(e[j].to,++col); } for (int i=1;i<=n;i++) if (id[i]!=-1) sum[id[i]]++; int tot=0;LL ans=1; for (int i=1;i<=col;i++) if (sum[i]) tot++,ans=ans*sum[i]; if (!tot) printf("2 %d\n",n*(n-1)/2); else printf("%d %lld\n",tot,ans); } return 0;}
【bzoj2730】 HNOI2012—矿场搭建
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。