有向图的强连通分量------最大半连通子图

一个有向图 G=(V,E)G=(V,E)

称为半连通的 (Semi-Connected),如果满足:∀u,v∈V∀u,v∈V

,满足 u→vu→v

或 v→uv→u

,即对于图中任意两点 u,vu,v

,存在一条 uu

到 vv

的有向路径或者从 vv

到 uu

的有向路径。若 G′=(V′,E′)G′=(V′,E′)

满足,E′E′

是 EE

中所有和 V′V′

有关的边,则称 G′G′

是 GG

的一个导出子图。若 G′G′

是 GG

的导出子图,且 G′G′

半连通,则称 G′G′

为 GG

的半连通子图。若 G′G′

是 GG

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

是 GG

的最大半连通子图。给定一个有向图 GG

,请求出 GG

的最大半连通子图拥有的节点数 KK

,以及不同的最大半连通子图的数目 CC

。由于 CC

可能比较大,仅要求输出 CC

对 XX

的余数。输入格式第一行包含三个整数 N,M,XN,M,X

。N,MN,M

分别表示图 GG

的点数与边数,XX

的意义如上文所述;接下来 MM

行,每行两个正整数 a,ba,b

,表示一条有向边 (a,b)(a,b)

。图中的每个点将编号为 11

到 NN

,保证输入中同一个 (a,b)(a,b)

不会出现两次。输出格式应包含两行。第一行包含一个整数 KK

,第二行包含整数 C mod XC mod X

。数据范围1≤N≤1051≤N≤105

,1≤M≤1061≤M≤106

,1≤X≤1081≤X≤108

输入样例:6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
输出样例:3
3

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 100010, M = 2000010;
typedef long long LL;
int n, m, mod;
int h[N], hs[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, scc_size[N];
int f[N], g[N];
void add(int h[], int a, int b){
 e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void tarjan(int u){
 dfn[u] = low[u] = ++timestamp;
 stk[++ top] = u, in_stk[u] = true;
  for (int i = h[u]; ~i; i = ne[i]){
  int j = e[i];
  if (!dfn[j]){
   tarjan(j);
   low[u] = min(low[u], low[j]); 
  }
  else if (in_stk[j])  low[u] = min(low[u], dfn[j]);
 }
  if (dfn[u] == low[u]){
  ++ scc_cnt;
  int y;
  do{
    y = stk[top --];
    in_stk[y] = false;
    id[y] = scc_cnt;
    scc_size[scc_cnt] ++;
  }while(y != u);
 }
}
int main(){
 memset(h, -1, sizeof h);
 memset(hs, -1, sizeof hs);
  scanf("%d%d%d", &n, &m, &mod);
 while(m --){
  int a, b;
  scanf("%d%d", &a, &b);
  add(h, a, b);
 }
  for (int i = 1; i <= n; i ++)
    if (!dfn[i])
     tarjan(i);
      unordered_set<LL> S;
 for (int i = 1; i <= n; i ++)
    for (int j = h[i]; ~j; j = ne[j]){
     int k = e[j];
     int a = id[i], b = id[k];
     LL hash = a * 1000000ll + b;
     if (a != b && !S.count(hash)){
      add(hs, a, b);
      S.insert(hash);
     }
    }
     for (int i = scc_cnt; i; i --){
  if (!f[i]){
   f[i] = scc_size[i];
   g[i] = 1;
  }
    for (int j = hs[i]; ~j; j = ne[j]){
   int k = e[j];
   if (f[k] < f[i] + scc_size[k]){
    f[k] = f[i] + scc_size[k];
    g[k] = g[i];
   }
   else  if (f[k] == f[i] + scc_size[k])   g[k] = (g[k] + g[i]) % mod;
  }
 }
  int maxf = 0, sum = 0;
 for (int i = 1; i <= scc_cnt; i ++)
    if (f[i] > maxf){
     maxf = f[i];
     sum = g[i];
    }
    else   if (f[i] == maxf)    sum = (sum + g[i]) % mod;
        cout << maxf << endl;
    cout << sum << endl;
        return 0;
}
发布了164 篇原创文章 · 获赞 112 · 访问量 6756

猜你喜欢

转载自blog.csdn.net/qq_45772483/article/details/105607141
今日推荐