zoukankan      html  css  js  c++  java
  • Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)

    P2272 [ZJOI2007]最大半连通子图

    题意

    题目描述

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

    输入格式

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

    输出格式

    应包含两行,第一行包含一个整数(K)。第二行包含整数(Cmod X)

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    3
    3
    

    说明

    对于(100\%)的数据,(Nle 100000,Mle 1000000,Xle 10^8)

    思路

    先来想两个问题:

    1. 该图是强连通图,那么答案是多少?
    2. 该图是有向无环图,那么答案是多少?

    对于第一个问题,任意两点互相可达,问题变得很简单,答案就是原图;对于第二个问题,我们可以直接(DAG DP)完美解决。

    那么对于任意的一张图,我们用(Tarjan)缩点之后,答案不久呼之欲出了吗?所以这题只需要在缩点之后的图上(DP)就好了。

    不过还有个细节:因为要求方案数,所以不能建重边。比如点(1)向点(2)建了两条边。从(1)点向周围拓展时,第一次扫描到(2),我们更新了(2)的答案;第二次扫描到(2),我们又更新了(2)的答案。这显然是不被允许的。所以开个(set)判断一下重边就好啦。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,LL> PLL;
    const LL MAXN=1e5+5,MAXM=1e6+5;
    LL n,m,p,ans1,ans2,tot,dfn[MAXN],low[MAXN];
    LL cnt,top[MAXN],to[MAXM],nex[MAXM];
    LL _cnt,_top[MAXN],_to[MAXM],_nex[MAXM];
    LL js,bel[MAXN],sz[MAXN],deg[MAXN],val[MAXN],tms[MAXN];
    bool vis[MAXN];
    stack<LL>S;
    set<PLL>SS;
    LL read()
    {
        LL re=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    void tarjan(LL now)
    {
        dfn[now]=low[now]=++tot,vis[now]=true,S.push(now);
        for(LL i=top[now];i;i=nex[i])
            if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
            else if(vis[to[i]]) low[now]=min(low[now],dfn[to[i]]);
        if(dfn[now]==low[now])
        {
            bel[now]=++js,vis[now]=false,sz[js]=1;
            while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,sz[js]++,S.pop();
            S.pop();
        }
    }
    void work()
    {
        memset(vis,false,sizeof vis);
        queue<LL>Q;
        for(LL i=1;i<=js;i++) if(!deg[i]) val[i]=sz[i],tms[i]=1,Q.push(i);
        while(!Q.empty())
        {
            LL now=Q.front();Q.pop();
            for(LL i=_top[now];i;i=_nex[i])
            {
                deg[_to[i]]--;
                if(vis[_to[i]]) continue;
                vis[_to[i]]=true;
                if(val[_to[i]]<val[now]+sz[_to[i]]) val[_to[i]]=val[now]+sz[_to[i]],tms[_to[i]]=tms[now];
                else if(val[_to[i]]==val[now]+sz[_to[i]]) tms[_to[i]]=(tms[_to[i]]+tms[now])%p;
                if(!deg[_to[i]]) Q.push(_to[i]);
            }
            for(LL i=_top[now];i;i=_nex[i]) vis[_to[i]]=false;
        }
    }
    int main()
    {
        n=read(),m=read(),p=read();
        while(m--)
        {
            LL x=read(),y=read();
            to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;
        }
        for(LL i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        for(LL i=1;i<=n;i++)
            for(LL j=top[i];j;j=nex[j])
                if(bel[i]!=bel[to[j]])
                {
                    if(SS.find(make_pair(bel[i],bel[to[j]]))!=SS.end()) continue;
                    _to[++_cnt]=bel[to[j]],_nex[_cnt]=_top[bel[i]],_top[bel[i]]=_cnt,deg[bel[to[j]]]++;
                    SS.insert(make_pair(bel[i],bel[to[j]]));
                }
        work();
        for(LL i=1;i<=js;i++)
            if(ans1<val[i]) ans1=val[i],ans2=tms[i];
            else if(ans1==val[i]) ans2=(ans2+tms[i])%p;
        printf("%lld
    %lld",ans1,ans2);
        return 0;
    }
    
  • 相关阅读:
    objectivec 多个参数的函数的例子
    EDM 电子邮件制作规范
    一封让老总流泪的辞职申请书
    10个优秀的JavaScript参考手册
    应聘需知
    理解内联(display:inline)和浮动(float:left;)的区别
    写CSS常见错误,童鞋们注意了
    15个css常识
    经典设计网站推荐
    2011年春运电话订火车票流程
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9895806.html
Copyright © 2011-2022 走看看