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

    这个题,翻译一下题面,就是一个连通图,找他的最长链的数量。。。

    所以说方法就比较明显了:tarjan缩点+拓扑+DP

    注意也是本题唯一坑点,拓扑DP的时候要考虑重复边的情况。。。

    呆码:

    #include<iostream>
    #include<cstdio>
    #define N 100010
    #define M 1000010
    using namespace std;
    
    struct asd{
        int nxt;
        int to;
    } a[M<<2],b[M];
    
    int head[M<<2],headd[M],t[N],dfn[N],low[N],stack[N];
    int num[N],belong[N],tmp[N],f[N],g[N],vis[N];
    int sum,number,top,cnt,n,m,mo,mx,ans;
    bool use[N];
    
    inline void add(int x,int y)
    {
        a[++sum].nxt=head[x];
        a[sum].to=y;
        head[x]=sum;
    }
    
    inline void bdd(int x,int y)
    {
        b[++sum].nxt=headd[x];
        b[sum].to=y;
        headd[x]=sum;
        t[y]++;
    }
    
    inline void tarjan(int u)
    {
        number++;
        dfn[u]=low[u]=number;
        stack[++top]=u;
        use[u]=1;
        for(int i=head[u];i;i=a[i].nxt)
        {
            int v=a[i].to;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(use[v])
                 low[u]=min(low[u],dfn[v]);
        }
        int v;
        if(dfn[u]==low[u])
        {
            cnt++;
            do{
                num[cnt]++;
                v=stack[top--];
                belong[v]=cnt;
                use[v]=0;
            }while(u!=v);
        }
    }
    
    inline void rebuild()
    {
        for(int i=1;i<=n;i++)
            for(int j=head[i];j;j=a[j].nxt)
                if(belong[i]!=belong[a[j].to])
                    bdd(belong[i],belong[a[j].to]);
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&mo);
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
    
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        sum=0; rebuild();
    
        int Head=0,Tail=0;
        for(int i=1;i<=cnt;i++)
        {
            if(!t[i]) tmp[++Tail]=i;
            f[i]=num[i]; g[i]=1;
        }
        while(Head<Tail)
        {
            int now=tmp[++Head];
            for(int i=headd[now];i;i=b[i].nxt)
            {
                int v=b[i].to; t[v]--;
                if(!t[v]) tmp[++Tail]=v;
                if(vis[v]==now) continue;
                if(f[now]+num[v]>f[v])
                {
                    f[v]=f[now]+num[v];
                    g[v]=g[now];
                }
                else if(f[now]+num[v]==f[v])
                     g[v]=(g[v]+g[now])%mo;
                vis[v]=now;
            }
        }
    
        for(int i=1;i<=cnt;i++)
        {
            if(f[i]>mx) mx=f[i],ans=g[i];
            else if(f[i]==mx) ans=(ans+g[i])%mo;
        }
    
        printf("%d
    %d",mx,ans);
    }
    代码
  • 相关阅读:
    练习一
    Oracle删除一个库里面的所有表
    bat脚本中,@echo on与@echo off的使用
    bat命令之执行脚本后不退出窗口
    福清游玩
    MyEclipse快捷键
    过滤器与拦截器
    Anaconda-Jupyter的简单使用
    pycharm简单配置
    4、 vim&shell
  • 原文地址:https://www.cnblogs.com/zzzyc/p/9257086.html
Copyright © 2011-2022 走看看