zoukankan      html  css  js  c++  java
  • [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
    %d
    ", ans, sum);
        return 0;
    }
  • 相关阅读:
    Reverse Words in a String II -- LeetCode
    计算两点间的距离,hdu-2001
    A + B Problem,hdu-1000
    ASCII码排序,hdu-2000
    定义#define
    break语句的使用
    判断一个数是否为素数
    用下面公式求π:
    Sum Problem-hdu-1001
    正三角形的外接圆面积,nyoj-274
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7779722.html
Copyright © 2011-2022 走看看