AcWing 1175 最大半连通子图

AcWing 1175

题目描述

一个有向图 G=(V,E) 称为半连通的 (Semi-Connected),如果满足:∀u,v∈V,满足 u→v 或 v→u,即对于图中任意两点 u,v,存在一条 u 到 v 的有向路径或者从 v 到 u 的有向路径。

若 G′=(V′,E′) 满足,E′ 是 E 中所有和 V′ 有关的边,则称 G′ 是 G 的一个导出子图。

若 G′ 是 G 的导出子图,且 G′ 半连通,则称 G′ 为 G 的半连通子图。

若 G′ 是 G 所有半连通子图中包含节点数最多的,则称 G′ 是 G 的最大半连通子图。

给定一个有向图 G,请求出 G 的最大半连通子图拥有的节点数 K,以及不同的最大半连通子图的数目 C。

由于 C 可能比较大,仅要求输出 C 对 X 的余数。

输入格式

第一行包含三个整数 N,M,X。N,M 分别表示图 G 的点数与边数,X 的意义如上文所述;

接下来 M 行,每行两个正整数 a,b,表示一条有向边 (a,b)。

图中的每个点将编号为 1 到 N,保证输入中同一个 (a,b) 不会出现两次。

输出格式

应包含两行。

第一行包含一个整数 K,第二行包含整数 C mod X。

数据范围

1≤N≤ 1 0 5 10^5 ,
1≤M≤ 1 0 6 10^6 ,
1≤X≤ 1 0 8 10^8

输入样例:

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

输出样例:

3
3

题解:

先用tarjan算法求出强连通分量,将原图进行缩点,原图变成了一个有向无环图,求最大半连通分量,其实就是在缩点后的图上找出最长路(点权为该强连通分量中的结点个数),顺便同计出条数(半连通子图的个数)。

注意点:

1.缩点时需要将边判重,否则会重复计算,并注意空间
2.连通分量递减的顺序一定是拓扑序,不用再做一遍拓扑排序

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#include <algorithm>
#include <utility>
using namespace std;
const int N = 100005;
const int M = 2000005; 
int head[N], nxt[M], pnt[M], E;
int dfn[N], low[N], Time;
int stac[N], top;
bool ins[N];
int scc, belong[N], Size[N];
int tsort[N], f, dp[N], cnt[N];
int head2[N];
set<long long> st; 
void add_edge(int h[], int a, int b){
	pnt[E] = b;
	nxt[E] = h[a];
	h[a] = E++;
}
void dfs(int u){
	dfn[u] = low[u] = ++Time;
	stac[++top] = u;
	ins[u] = 1;
	int i, v;
	for(i = head[u]; i != -1; i = nxt[i]){
		v = pnt[i];
		if(!dfn[v]){
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if(ins[v])
			low[u] = min(low[u], dfn[v]);
	}
	int s;
	if(dfn[u] == low[u]){
		scc++;
		Size[scc] = 0;
		do{
			s = stac[top];
			top--;
			ins[s] = 0;
			Size[scc]++;
			belong[s] = scc;
		}while(s != u);
		tsort[++f] = scc;
	}
}
int main(){
	int n, m, x, i, j, k;
	int a, b;
	scanf("%d%d%d", &n, &m, &x);
	E = 0;
	memset(head, -1, sizeof(head));
	memset(head2, -1, sizeof(head2));
	for(i = 1; i <= m; i++){
		scanf("%d%d", &a, &b);
		add_edge(head, a, b);
	}
	Time = 0;
	top = 0;
	scc = 0;
	f = 0;
	for(i = 1; i <= n; i++)
		if(!dfn[i]) 
			dfs(i);
	long long tmp;
	for(i = 1; i <= n; i++){
		for(j = head[i]; j != -1; j = nxt[j]){
			k = pnt[j];
			if(belong[i] == belong[k]) continue;
			tmp = (long long)belong[i] * N + belong[k];
			if(st.count(tmp)) continue;
			add_edge(head2, belong[i], belong[k]);
			st.insert(tmp);
		}
	}
	int ans1 = 0, ans2 = 0;
	for(i = scc; i >= 1; i--){
		if(dp[i] == 0)
			cnt[i] = 1;
		dp[i] += Size[i];
		if(dp[i] > ans1){
			ans1 = dp[i];
			ans2 = cnt[i] % x;
		}
		else if(dp[i] == ans1)
			ans2 = (ans2 + cnt[i]) % x;
		for(j = head2[i]; j != -1; j = nxt[j]){
			k = pnt[j];
			if(dp[i] > dp[k]){
				dp[k] = dp[i];
				cnt[k] = cnt[i];
			}
			else if(dp[i] == dp[k])
				cnt[k] = (cnt[k] + cnt[i]) % x;
		}
	}
	printf("%d\n%d\n", ans1, ans2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/linwenqidbk/article/details/105473613
今日推荐