zoukankan      html  css  js  c++  java
  • P3225 [HNOI2012]矿场搭建

    题目描述

    煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。

    请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

    题解

    这道题我们首先进行(tarjan)求出割点,然后(dfs)扫一下所有的连通块。

    我们对每一个连通块中的割点数目进行讨论:

    如果没有割点,我们需要建造两个救援出口,而方案数为(C(n,2) = n * (n - 1) / 2)

    如果只有一个割点,那么我们只要建造一个救援出口就好了,方案数为(n)

    如果有两个或两个以上个割点,那么割点分成的部分就可以互通,所以就不需要建造救援出口了。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 605;
    int n, m, dfn[N], cut[N], num, low[N], head[N], tot, vis[N], rt, flag, sum, cnt1, cnt2, id, now;
    ll ans;
    struct node{int to, nex;}a[N << 1];
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void add(int x, int y) {a[++ tot].to = y; a[tot].nex = head[x]; head[x] = tot;}
    void tarjan(int x, int fa)
    {
    	dfn[x] = low[x] = ++ num;
    	for(int i = head[x]; i; i = a[i].nex)
    	{
    		int y = a[i].to;
    		if(!dfn[y])
    		{
    			tarjan(y, x); low[x] = min(low[x], low[y]);
    			if(low[y] >= dfn[x])
    			{
    				if(x != rt) cut[x] = 1;
    				else flag ++;
    			}
    		}
    		else if(y != fa) low[x] = min(low[x], dfn[y]);
    	}
    	if(x == rt && flag > 1) cut[x] = 1;
    }
    void dfs(int x)
    {
    	cnt1 ++; vis[x] = id;
    	for(int i = head[x]; i; i = a[i].nex)
    	{
    		int y = a[i].to;
    		if(cut[y] && vis[y] != id) {cnt2 ++; vis[y] = id;}
    		if(!vis[y]) dfs(y);
    	}
    }
    void work()
    {
    	while((m = read()))
    	{
    		for(int i = 1; i <= n; i ++) dfn[i] = head[i] = cut[i] = vis[i] = 0;
    		num = sum = id = tot = n = 0; ans = 1;//n
    		for(int i = 1, x, y; i <= m; i ++) {x = read(); y = read(); add(x, y); add(y, x); n = max(n, max(x, y));}
    		for(int i = 1; i <= n; i ++) if(!dfn[i]) rt = i, flag = 0, tarjan(i, 0);
    		for(int i = 1; i <= n; i ++)
    		{
    			if(cut[i] || vis[i]) continue;
    			++ id; cnt1 = cnt2 = 0; dfs(i);
    			if(cnt2 == 0) sum += 2, ans = ans * (cnt1 - 1) * cnt1 / 2;
    			else if(cnt2 == 1) sum += 1, ans = ans * cnt1;
    		}
    		printf("Case %d: %d %lld
    ", ++ now, sum, ans);
    	}
    }
    int main() {return work(), 0;}
    
  • 相关阅读:
    cakephp异常机制
    你的效率是整理出来的——张一驰
    eclipse常用总结
    cakephp写Lib要点
    代码整洁之道-马丁-第3章 函数
    PHP静态方法如何编写
    编程常用工具
    代码大全(第二版)
    PHP实现AES对称加密
    【pytest】(三) pytest运行多个文件
  • 原文地址:https://www.cnblogs.com/Sunny-r/p/12599807.html
Copyright © 2011-2022 走看看