您的位置:首页 > 其它

[双连通分量]LA5135 Mining your own business

2017-08-08 20:34 441 查看

题意

给出一个连通图,求在这个图中,至少给多少个点染色,使得在删除了任意一个点后,每个连通分量里都有一个染色的点,并且求方案数。

思路

首先先求一次双连通分量,然后用贪心的思想发现,如果把割点染色,显然一旦割点被删就会有多个连通分量中没有染色点,所以给割点染色是不好的。

那么只要将一个双连通分量中的一个非割点染色,那么就算割点被删,它也能自成一体,如果所有的双连通分量都是这样,即使这个点被删,还可以连到别的双连通分量里。

那么如果是有两个或者更多割点的呢,很容易发现,在这里无论哪个点被删,都可以跑到别的双连通分量中。

那么就是说,只需要在一个只有一个割点的双连通分量里染一个不是割点的点就好了。

但是还有一种特殊情况,就是原图是一个双连通图时,就要染两个点,因为如果去掉了一个点,还要给另一个点染才行。

所以最后代码是很好写的,基本直接套模板

代码

#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 200010,
MAXM = 200010;

struct Edge {
int u, v, ne;
Edge() {}
Edge(int in_u, int in_v, int in_ne) {
u = in_u;
v = in_v;
ne = in_ne;
}
} e[MAXM];

int head[MAXN], m_cnt;

void init() {
memset(head, -1, sizeof head);
m_cnt = 0;
}

void AddEdge(int u, int v) {
e[m_cnt] = Edge(u, v, head[u]);
head[u] = m_cnt++;
e[m_cnt] = Edge(v, u, head[v]);
head[v] = m_cnt++;
}

stack  S;
int bccno[MAXN], pre[MAXN], dfs_clock, bcc_cnt;
bool iscut[MAXN];
vector  bcc[MAXN];

int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i = head[u]; ~i; i = e[i].ne) {
int v = e[i].v;
if(!pre[v]) {
S.push(e[i]);
child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if(lowv >= 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] < pre[u] && v != fa) {
S.push(e[i]);
lowu = min(lowu, pre[v]);
}
}
}
if(fa < 0 && child == 1) {
iscut[u] = 0;
}
return lowu;
}

void find_bcc(int n) {
memset(pre, 0, sizeof pre);
memset(iscut, 0, sizeof iscut);
memset(bccno, 0, sizeof bccno);

dfs_clock = bcc_cnt = 0;

for(int i = 1; i <= n; ++i) {
if(!pre[i]) {
dfs(i, -1);
}
}
}

int main(void) {
int m, n;
int Case = 0;
while(~scanf("%d", &m) && m) {
init();
n = 0;
for(int i = 0; i < m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
n = max(n, max(u, v));
}

find_bcc(n);

long long 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 *= (long long) (bcc[i].size() - 1);
}
}
if(bcc_cnt == 1) {
ans1 =  2;
ans2 = bcc[1].size() * (bcc[1].size() - 1) / 2;
}
printf("Case %d: %lld %lld\n", ++Case, ans1, ans2);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: