[BZOJ1093][ZJOI2007]最大半连通子图

Posted Elder_Giang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1093][ZJOI2007]最大半连通子图相关的知识,希望对你有一定的参考价值。

1093: [ZJOI2007]最大半连通子图

Time Limit: 30 Sec  Memory Limit: 162 MB Submit: 3710  Solved: 1464 [Submit][Status][Discuss]

Description

  一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G‘=(V‘,E‘)满足V‘?V,E‘是E中所有跟V‘有关的边, 则称G‘是G的一个导出子图。若G‘是G的导出子图,且G‘半连通,则称G‘为G的半连通子图。若G‘是G所有半连通子图 中包含节点数最多的,则称G‘是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K ,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

Input

  第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整 数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1 00000, M ≤1000000;对于100%的数据, X ≤10^8

Output

  应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

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

Sample Output

3
3
 
缩点后求DAG上最长链(点权)以及最长链的方案数
注意判重边
 
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10, maxm = 1000000 + 10;
int n, m, mod;
struct Edge{
    int to, next;
    Edge(){}
    Edge(int _t, int _n): to(_t), next(_n){}
}e[maxm * 2];
int fir[maxn * 2] = {0}, cnt = 0;
inline void add(int u, int v){
    e[++cnt] = Edge(v, fir[u]); fir[u] = cnt;
}
int belong[maxn], siz[maxn * 2] = {0}, bcnt = 0;
int dfn[maxn], low[maxn], index = 0;
int sta[maxn], top = 0;
bool ins[maxn] = {false};
void tarjan(int u){
    ins[u] = true;
    sta[++top] = u;
    dfn[u] = low[u] = ++index;
    for(int v, i = fir[u]; i; i = e[i].next){
        v = e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(ins[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]){
        int now;
        bcnt++;
        do{
            now = sta[top--];
            ins[now] = false;
            belong[now] = bcnt;
            siz[bcnt]++;
        }while(now != u);
    }
}
int ind[maxn * 2] = {0}, q[maxn], h, t;
void tsort(){
    for(int v, u = 1; u <= n; u++)
        for(int i = fir[u]; i; i = e[i].next){
            v = e[i].to;
            if(belong[v] != belong[u]){
                ind[belong[v]]++;
                add(belong[u], belong[v]);
            }
        }
    h = t = 0;
    for(int i = n + 1; i <= bcnt; i++)
        if(!ind[i]) q[t++] = i;
    int u, v;
    while(h != t){
        u = q[h++];
        for(int i = fir[u]; i; i = e[i].next){
            v = e[i].to;
            ind[v]--;
            if(!ind[v]) q[t++] = v;
        }
    }
}
int f[maxn * 2], g[maxn * 2];
int mark[maxn * 2] = {0};
void dp(){
    int u, v;
    for(int i = h; ~i; i--){
        u = q[i];
        f[u] = siz[u];
        g[u] = 1;
        for(int j = fir[u]; j; j = e[j].next){
            v = e[j].to;
            if(mark[v] == u) continue;
            mark[v] = u;
            if(f[v] + siz[u] > f[u]){
                f[u] = f[v] + siz[u];
                g[u] = g[v];
            }
            else if(f[v] + siz[u] == f[u]) g[u] = (g[u] + g[v]) % mod;
        }
    }
}
int main(){
    scanf("%d %d %d", &n, &m, &mod);
    for(int u, v, i = 1; i <= m; i++){
        scanf("%d %d", &u, &v);
        add(u, v);
    }
    bcnt = n;
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i);
    tsort();
    dp();
    int ans = 0, sum = 0;
    for(int i = n + 1; i <= bcnt; i++){
        if(f[i] > ans){
            ans = f[i];
            sum = g[i];
        }
        else if(f[i] == ans) sum = (sum + g[i]) % mod;
    }
    printf("%d\n%d\n", ans, sum);
    return 0;
}

 

以上是关于[BZOJ1093][ZJOI2007]最大半连通子图的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1093: [ZJOI2007]最大半连通子图

bzoj 1093: [ZJOI2007]最大半连通子图

bzoj 1093: [ZJOI2007]最大半连通子图tarjan+拓扑排序+dp

BZOJ1093ZJOI2007最大半联通子图 [拓扑][DP][Tarjan]

bzoj1093 [ZJOI2007]最大半联通子图

tarjan 拓扑排序 dpbzoj1093: [ZJOI2007]最大半连通子图