zoukankan      html  css  js  c++  java
  • 【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-1)/2);
    		else printf("%d %lld
    ",tot,ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    【BZOJ】1045: [HAOI2008]糖果传递(中位数)
    【BZOJ】1011: [HNOI2008]遥远的行星(近似)
    【BZOJ】1034: [ZJOI2008]泡泡堂BNB(贪心)
    【BZOJ】1029: [JSOI2007]建筑抢修(贪心)
    【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)
    【BZOJ】1010: [HNOI2008]玩具装箱toy(dp+斜率优化)
    noip2014滚粗记
    【NOIP模拟题】Permutation(dp+高精度)
    MySQL 关于自定义函数的操作
    MySQL 关于存储过程的操作
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6065994.html
Copyright © 2011-2022 走看看