UVA 1108 - Mining Your Own Business(双连通分量)

UVA 1108 - Mining Your Own Business

题目链接

题意:给定一个连通图,设置一个些安全点,使得其他任意一些节点崩塌后,其他点都能到一个安全点,问安全点最小数量和情况数

思路:

#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <map>
using namespace std;

const int N = 50005;

struct Edge {
	int u, v;
	Edge() {}
	Edge(int u, int v) {
		this->u = u;
		this->v = v;
	}
};

int pre[N], bccno[N], dfs_clock, bcc_cnt;
bool iscut[N];

vector<int> g[N], bcc[N];
stack<Edge> S;

int dfs_bcc(int u, int fa) {
	int lowu = pre[u] = ++dfs_clock;
	int child = 0;
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i];
		Edge e = Edge(u, v);
		if (!pre[v]) {
			S.push(e);
			child++;
			int lowv = dfs_bcc(v, u);
			lowu = min(lowu, lowv);
			if (lowv >= pre[u]) {
				iscut[u] = true;
				bcc_cnt++; bcc[bcc_cnt].clear(); //start from 1
				while(1) {
					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] < pre[u] && v != fa) {
			S.push(e);
			lowu = min(lowu, pre[v]);
		}
	}
	if (fa < 0 && child == 1) iscut[u] = false;
	return lowu;
}

int st;

void find_bcc() {
	memset(pre, 0, sizeof(pre));
	memset(iscut, 0, sizeof(iscut));
	memset(bccno, 0, sizeof(bccno));
	dfs_clock = bcc_cnt = 0;
	dfs_bcc(0, -1);
}

int n, m;

typedef long long ll;

void solve() {
	ll ans1 = 0, ans2 = 1;
	for (int i = 1; i <= bcc_cnt; i++) {
		int cut_cnt = 0;
		for (int j = 0; j < bcc[i].size(); j++)
			if (iscut[bcc[i][j]]) cut_cnt++;
		if (cut_cnt == 1) {
			ans1++;
			ans2 *= (ll)(bcc[i].size() - cut_cnt);
		}
	}
	if (bcc_cnt == 1) {
		ans1 = 2;
		ans2 = (ll)bcc[1].size() * (bcc[1].size() - 1) / 2;
	}
	printf(" %lld %lld\n", ans1, ans2);
}

int main() {
	int cas = 0;
	while (~scanf("%d", &m) && m) {
		int u, v, Max = 0;
		while (m--) {
			scanf("%d%d", &u, &v);
			u--; v--;
			g[u].push_back(v);
			g[v].push_back(u);
			Max = max(Max, u);
			Max = max(Max, v);
		}
		find_bcc();
		printf("Case %d:", ++cas);
		solve();
		for (int i = 0; i <= Max; i++)
			g[i].clear();
	}
	return 0;
}
时间: 2024-10-19 15:57:54

UVA 1108 - Mining Your Own Business(双连通分量)的相关文章

UVALive - 5135 Mining Your Own Business(双连通分量)

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数 解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点 如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部

UVALive 5135 Mining Your Own Business 双连通分量 2011final

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点.因为不同的连通分量最多只有一个公共点,那一定是割点.可以发现,涂黑割点是不划算的,而且在 一个点-双连通分量中涂黑两个黑点也是不划算的.所以只有当点-双连通分量只有一个割点时

UVA 1108 - Mining Your Own Business

刘汝佳书上都给出了完整的代码 在这里理一下思路: 由题意知肯定存在一个或者多个双连通分量: 假设某一个双连通分量有割顶.那太平井一定不能打在割顶上. 而是选择割顶之外的随意一个点: 假设没有割顶,则要在该双连通分量上打两个井 至于打井方案.见代码 #include <cstdio> #include <cstring> #include <vector> #include <stack> #include <map> using namespac

UVA 10972 - RevolC FaeLoN(边-双连通分量)

UVA 10972 - RevolC FaeLoN 题目链接 题意:给定一个无向图(不一定全连通).如今把边定向,问还要加入几条边使得图强连通 思路:先求出边-双连通分量,每一个连通分量都能定向,然后缩点.转化为欧拉回路,假设每一个点度数都是大于等于2的偶数就是回路,也就是强连通了,所以计算度数为0和1的个数.一条边能添加两个度数.所以答案为所以仅仅要再加入上(a + 1) / 2 + b条边就能够了.注意特判一開始就已经是边-双连通分量的情况.答案应该为0 代码: #include <cstd

UVA - 10972 RevolC FaeLoN (边双连通分量)

题目大意:给定一个无向图,要求你把所有的无向边变成有向边,并且添加最少的有向边,使得新的有向图强连通 解题思路:这题和POJ - 3352 Road Construction 类似,只不过这题给的不一定是连通图,有可能缩点后出现孤立的点,但大体的思路是一样的 前面的就不详说了,可以看戳这里里面已经写了,这里讲一下怎么处理孤立的点 如果有n个点,要求在这n个点间添加有向边,使得这n个点变成强连通,那么需要添加的边的数量为n 有了上面这个结论,求的时候就比较好办了,处理的时候,只需要统计出所有度为1

hdu 3844 Mining Your Own Business (点双连通分量)

Mining Your Own Business Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1392    Accepted Submission(s): 219 Problem Description John Digger is the owner of a large illudium phosdex mine. The m

hdu3844 Mining Your Own Business,无向图的双连通分量

点击打开链接 无向图的双连通分量 #include<cstdio> #include<stack> #include<vector> #include<map> #include<algorithm> #include<cstring> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long lo

UVA 1364 - Knights of the Round Table (找双连通分量 + 二分图染色法判断)

都特么别说话,我先A了这道题! 卧槽啊.....! 题意来自 kuangbin: 亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突, 并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有如下要求: 1.  相互憎恨的两个骑士不能坐在直接相邻的2个位置: 2.  出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果. 注意:1.所给出的憎恨关系一定是双向的,不存在单向憎恨关系. 2.由于是圆桌会议,则每个出席的骑士身边必定刚好有2个骑士. 即每个骑士的座位两边都

uva 10792 无向图的边双连通分量

题意:给定一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,是的新的无向图连通. 首先,这题是先要明白,有向图的强连通分量,如果把所有的边都变成无向的,就是无向图的边双连通分量. 恩,本来以为边双连通分量又是求桥又是绕过桥dfs很麻烦想想就不想做..后来无意中在别人的题解上看到一个结论(好厉害..) 方法如下: 对无向图执行dfs求割点,然后对于任意点i和j,如果low[i]==low[j],那么它们属于同一个边-双连通分量 (点-双连通分量内的两个点的low[]值不一定相同,自己画