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


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

    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 ≤100000, 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
    题解Here!

    首先一个强连通缩点,把图变成一个 DAG 。

    然后就是求最长链与最长链个数。

    求最长链就直接拓扑排序一下。

    个数呢?

    这个要 DP 一下。

    本蒟蒻看到 DP 就不会了。。。

    设 f [ i ] 表示图中以 i 为终点的最长链个数,则 f [ i ] 等于与 i 连通并且距离是起点到 i 的最长距离的点的 f 值之和。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 100010
    using namespace std;
    int n,m,p,c=1;
    int num[MAXN],head[MAXN],indegree[MAXN],vis[MAXN],f[MAXN],g[MAXN];
    struct Graph{
        int next,to;
    }a[MAXN*10];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    inline void add(int x,int y){
        a[c].to=y;a[c].next=head[x];head[x]=c++;
    }
    namespace Tarjan{
        int c=1,d=1,s=0,top=1;
        int cstack[MAXN],head[MAXN],deep[MAXN],low[MAXN],colour[MAXN];
        bool vis[MAXN];
        struct Graph{
            int next,to;
        }edge[MAXN*10];
        inline void add_edge(int x,int y){
            edge[c].to=y;edge[c].next=head[x];head[x]=c++;
        }
        void work(int x){
            deep[x]=low[x]=d++;
            vis[x]=true;
            cstack[top++]=x;
            for(int i=head[x];i;i=edge[i].next){
                int v=edge[i].to;
                if(!deep[v]){
                    work(v);
                    low[x]=min(low[x],low[v]);
                }
                else if(vis[v])
                low[x]=min(low[x],deep[v]);
            }
            if(low[x]==deep[x]){
                s++;
                do{
                    colour[cstack[top-1]]=s;
                    vis[cstack[top-1]]=false;
                }while(cstack[--top]!=x);
            }
        }
        void solve(){
            int x,y;
            for(int i=1;i<=m;i++){
                x=read();y=read();
                add_edge(x,y);
            }
            for(int i=1;i<=n;i++)if(!deep[i])work(i);
            for(int i=1;i<=n;i++)num[colour[i]]++;
            for(int i=1;i<=n;i++)
            for(int j=head[i];j;j=edge[j].next){
                int v=edge[j].to;
                if(colour[v]!=colour[i]){
                    add(colour[i],colour[v]);
                    indegree[colour[v]]++;
                }
            }
            n=s;
        }
    }
    void topsort(){
        int u,v;
        queue<int> q;
        for(int i=1;i<=n;i++){
            if(!indegree[i])q.push(i);
            f[i]=num[i];g[i]=1;
        }
        while(!q.empty()){
            u=q.front();
            q.pop();
            for(int i=head[u];i;i=a[i].next){
                v=a[i].to;
                indegree[v]--;
                if(!indegree[v])q.push(v);
                if(vis[v]==u)continue;
                if(f[u]+num[v]>f[v]){
                    f[v]=f[u]+num[v];
                    g[v]=g[u];
                }
                else if(f[u]+num[v]==f[v])g[v]=(g[v]+g[u])%p;
                vis[v]=u;
            }
        }
    }
    void work(){
        int maxn=0,ans=0;
        for(int i=1;i<=n;i++){
            if(f[i]>maxn){maxn=f[i];ans=g[i];}
            else if(f[i]==maxn)ans=(ans+g[i])%p;
        }
        printf("%d
    %d
    ",maxn,ans);
    }
    void init(){
        n=read();m=read();p=read();
        Tarjan::solve();
        topsort();
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    [C#]App.Config
    [转][JS]修改链接中的参数
    [转][Oracle]常见报错及处理
    [转]截图软件分享
    [转][C#]手写 Socket 服务端
    3.6的pprint写法改变了:pprint.pprint()
    版本优化-test
    python爬取豆瓣小组700+话题加回复啦啦啦python open file with a variable name
    爬豆瓣被封的解决方案
    去除列表中字符串中的空格换行等
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9393537.html
Copyright © 2020-2023  润新知