zoukankan      html  css  js  c++  java
  • BZOJ 1093: [ZJOI2007]最大半连通子图

    Time Limit: 30 Sec Memory Limit: 162 MB
    Submit: 4068 Solved: 1638
    [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

    解题思路

    因为如果图中有环,环上的点能互相到达,答案一定更优,所以我们先缩点。缩完点之后最优的答案的开始一定在度数为0的点,所以我们思考拓补排序。设Num[x]为x的最大链长,dp[x]为x点处最大链长的总路径数。转移时如果Num[u ]< u点中小点的数量+Num[x],则dp[u]=dp[x],Num[u]=Num[x]+u点中小点的数量。如果Num[u]=Num[x]+u中小点的数量,dp[u]+=dp[x],最后答案取那些Num为mx的dp值之和。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    
    using namespace std;
    const int MAXN = 500005;
    const int MAXM = 1000005;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
        return x*f;
    }
    
    int n,m,mod;
    int head[MAXN],cnt;
    
    struct Edge{
        int nxt,to,fr;
    }e[MAXM<<1];
    
    queue<int> q;
    
    inline void add(int bg,int ed){
        e[++cnt].to=ed,e[cnt].fr=bg,e[cnt].nxt=head[bg],head[bg]=cnt;
    }
    
    int dfn[MAXN],low[MAXN];
    int sta[MAXN],top,num,col[MAXN];
    int col_num,sum[MAXN],Num[MAXN],dp[MAXN];
    bool vis[MAXN];
    
    inline void tarjan(int x){
        dfn[x]=low[x]=++num;
        sta[++top]=x;
        vis[x]=1;
        for(register int i=head[x];i;i=e[i].nxt){
            int u=e[i].to;
            if(!dfn[u]){
                tarjan(u);
                low[x]=min(low[x],low[u]);
            }
            else if(vis[u])
                low[x]=min(low[x],dfn[u]);
        }
        if(low[x]==dfn[x]){
            int tot=0;
            col_num++;
            vis[x]=0;
            while(sta[top]!=x){
                tot++;
                vis[sta[top]]=0;
                col[sta[top]]=col_num;
                top--;
            }
            top--;tot++;
            col[x]=col_num;
            sum[col_num]=tot;
        }
    }
    
    int head_[MAXN],cnt_;
    int to_[MAXM],nxt_[MAXM];
    int ans,du[MAXN],mx;
    int bl[MAXN];
    
    inline void add_(int bg,int ed){
        to_[++cnt_]=ed,nxt_[cnt_]=head_[bg],head_[bg]=cnt_;
    }
    
    inline void dfs(){
        while(q.size()){
            int x=q.front();q.pop();
            mx=max(mx,Num[x]);
            for(register int i=head_[x];i;i=nxt_[i]){
                int u=to_[i];du[u]--;
                if(!du[u]) q.push(u);
                if(bl[u]==x) continue;
                if(Num[u]<Num[x]+sum[u]) {
                    Num[u]=Num[x]+sum[u];
                    dp[u]=dp[x];
                }
                else if(Num[u]==Num[x]+sum[u]){
                    dp[u]+=dp[x];
                    dp[u]%=mod;
                }
                bl[u]=x;
            }
        }
    }
    
    inline bool cmp(Edge A,Edge B){
        return A.fr<B.fr;
    }
    
    int main(){
        n=rd();m=rd();mod=rd();
        int xx=0,y=0;
        for(register int i=1;i<=m;i++){
            xx=rd(),y=rd();
            add(xx,y); 
        }
        for(register int i=1;i<=n;i++) 
            if(!dfn[i]) tarjan(i);
        for(register int i=1;i<=m;i++)
            e[i].fr=col[e[i].fr],e[i].to=col[e[i].to];
        for(register int i=1;i<=m;i++)
            if(e[i].fr!=e[i].to){
                add_(e[i].fr,e[i].to);
                du[e[i].to]++;
            }
        for(register int i=1;i<=col_num;i++)
            if(!du[i]) q.push(i),Num[i]=sum[i],dp[i]=1;
        dfs();
        for(register int i=1;i<=col_num;i++)
            if(Num[i]==mx) ans+=dp[i],ans%=mod;
        printf("%d
    %d",mx,ans);
    }
  • 相关阅读:
    html5和css3的新特性
    实现全选按钮的js代码
    window.location对象获取浏览器地址栏的地址信息
    珍爱网前端笔试题之九宫格的实现
    c# array arraylist list
    解决visual studio不能发现单元测试、无法运行单元测试的方法
    Linux 学习笔记
    C++语言学习
    C语言学习
    日志打印,设置开关类【编程技巧】
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676981.html
Copyright © 2011-2022 走看看