zoukankan      html  css  js  c++  java
  • [ZJOI2007] 最大半联通子图

    最大半联通子图

    题目描述

    一个有向图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的余数。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    3
    3

    说明

    对于100%的数据, (N≤100000,M≤1000000,X≤10^8)

    题解

    bzoj1093

    我们把题目所给的图画出来

    题目要求求出一条路径,这条路径经过的点要最多,并输出这种路径的条数
    可以发现,1,2两个点是可以互相到达的,那么就可以缩点,记录一下强连通分量内的点的个数,方便以后的操作

    做到这里其实当时我是不知道接下来怎么做的,所以就打了个搜索
    但是把缩点之后拿出来一看,突然就有了思路
    因为原图是一个有向图,缩点之后就变成DAG,那么我们就可以topsort一下,确定我们记录的顺序,再然后发现可以dp

    那么自然而然的最值就出来了,怎么统计方案数?
    做过最短路计数的应该比较容易理解
    在topsort中,对与一个从队列中取出的点u,和它可以到达的其中一个点v
    如果被u更新的答案比原来v的答案更优,那么v的方案数就由u延续下来
    也就是

    if(dp[v]<dp[u]+num[v])//其中num[i]为i这个强连通分量内点的个数
    dp[v]=dp[u]+num[v],cnt[v]=cnt[u]
    

    如果被u更新的答案与v之前的答案一样,那么说明又多了一些方案可以到达这个答案

    if(dp[v]==dp[u]+num[v]) 
    cnt[v]+=cnt[u];
    

    那么整个思路应该就出来了

    1. 对原图缩点
    2. 对新的DAG重新建边,注意一点,缩点直接建边会有很多重复的边,所以要去重
    3. 统计入度为0的点,并加入队列进行topsort并dp
    4. 统计答案

    Code

    #include<bits/stdc++.h>
    #define Min(a,b) (a)<(b)?(a):(b)
    #define Max(a,b) (a)>(b)?(a):(b)
    using namespace std;
    typedef long long lol;
    const lol N=100010,M=1000010;
    
    void in(lol &ans)
    {
        ans=0;lol f=1;char i=getchar();
        while(i<'0' || i>'9') {if(i=='-') f=-1;i=getchar();}
        while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
        ans*=f;
    }
    
    stack<lol>s;
    lol n,m,cnt,mod,dfscnt,scc,t;
    lol ans,sum;
    lol to[M<<1],nex[M<<1],head[N];
    lol low[N],dfn[N],sccno[N],num[N],dp[N],dg[N],tq[N];
    
    struct E{
        lol x,y;
    }e[M],A[M];
    
    inline void add(lol a,lol b) {
        to[++cnt]=b;
        nex[cnt]=head[a];
        head[a]=cnt;
    }
    
    bool cmp(E a,E b) {
        if(a.x==b.x) return a.y<b.y;
        return a.x<b.x;
    }
    
    void tarjan(lol u)
    {
        dfn[u]= low[u] = ++dfscnt; s.push(u);
        for(lol i=head[u];i;i=nex[i]) 
            if(!dfn[to[i]]) tarjan(to[i]),low[u]=Min(low[u],low[to[i]]);
            else if(!sccno[to[i]]) low[u]=Min(low[u],dfn[to[i]]);
        if(low[u]==dfn[u]) {
            scc++;
            while(1) {
                lol x=s.top(); s.pop(); num[scc]++; sccno[x]=scc;
                if(x==u) break;
            }
        }
    }
    
    void topsort_dp()
    {
        queue<lol>q;
        for(lol i=1;i<=scc;i++) if(!dg[i]) q.push(i),dp[i]=num[i],tq[i]=1;
        while(!q.empty()) {
            lol u=q.front(); q.pop();
            for(lol i=head[u];i;i=nex[i]) {
                if(dp[to[i]]<dp[u]+num[to[i]]) dp[to[i]]=dp[u]+num[to[i]],tq[to[i]]=tq[u];
                else if(dp[to[i]]==dp[u]+num[to[i]]) (tq[to[i]]+=tq[u])%=mod;
                if(!(--dg[to[i]])) q.push(to[i]);
            }
        }
    }
    
    int main()
    {
        in(n), in(m) , in(mod);
        for(lol i=1;i<=m;i++) {
            lol a,b; in(a),in(b);
            add(a,b); e[i]=(E) {a,b};
        }
        for(lol i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        cnt=0; memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++) {
            int fx=sccno[e[i].x],fy=sccno[e[i].y];
            if(fx!=fy) A[++t] = (E) {fx,fy};
        }
        sort(A+1,A+1+t,cmp);
        for(lol i=1;i<=t;i++)
            if(A[i].x!=A[i-1].x || A[i].y!=A[i-1].y)
                add(A[i].x,A[i].y),dg[A[i].y]++;
        topsort_dp();
        for(int i=1;i<=scc;i++) {
            if(dp[i]>ans) {ans=dp[i],sum=tq[i];}
            else if(dp[i]==ans) (sum+=tq[i])%=mod;
        }
        printf("%lld
    %lld
    ",ans,sum);
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    如何选择RabbitMQ的消息保存方式?
    一次Flannel和Docker网络不通定位问题
    flannel
    vsftp设置不同用户登录ftp的根目录不同
    nginx反向代理服务器获取不到端口的问题的解决办法
    RabbitMQ 内存控制 硬盘控制
    -bash: fork: Cannot allocate memory
    redis info
    nginx第三方模块---nginx-sticky-module的使用(基于cookie的会话保持)
    Haproxy的三种保持客户端会话保持方式
  • 原文地址:https://www.cnblogs.com/real-l/p/9523294.html
Copyright © 2011-2022 走看看