• LOJ-10092(最大半连通子图)


    题目连通:传送门

    思路:

    题目定义很清晰,然后就不会了QAQ……

    后来看了书,先缩点,然后再用拓扑排序找到最长的链子的节点数(因为缩点后所有点都是一个强连通分量,所以找最长的链子就是最大限度包含

    点的半连通子图)然后用dp求出由多少个长度相同的链子(e数组记录从开始到i节点所有的方案数,dis数组表示链子的节点个数,每次找到更长的链子时就更新数组,然后最后求出多少个满足最长链子的方案)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 1e6+5;
    int head[maxn],next[maxn],ver[maxn],tot;
    int num[maxn],low[maxn],tim,co[maxn],si[maxn],col;
    int st[maxn],que[maxn],top,t,w;
    int du[maxn],e[maxn],ans,anss,m,n,MOD;
    int x[maxn],y[maxn],nu[maxn],dis[maxn];
    int MIN(int a,int b)
    {
        return a<b?a:b;
    }
    void addedge(int u,int v)
    {
        ver[++tot]=v;next[tot]=head[u];head[u]=tot;
    }
    void Tarjan(int u)
    {
        low[u]=num[u]=++tim;
        st[++top]=u;
        for(int i=head[u];i;i=next[i]){
            int v=ver[i];
            if(!num[v]){
                Tarjan(v);
                low[u]=MIN(low[u],low[v]);
            }
            else if(!co[v]) low[u]=MIN(low[u],num[v]);
        }
        if(num[u]==low[u]){
            col++;
            si[col]++;
            co[u]=col;
            while(u!=st[top]){
                si[col]++;
                co[st[top]]=col;
                top--;
            }
            top--;
        }
    }
    bool cmp(int a,int b)
    {
        if(x[a]!=x[b]) return x[a]<x[b];
        else return y[a]<y[b];
    }
    void Remove()
    {
        for(int i=1;i<=m;i++){
            nu[i]=i;
            x[i]=co[x[i]];
            y[i]=co[y[i]];
        }
        sort(nu+1,nu+1+m,cmp);
    }
    void Build()
    {
        tot=0;
        memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++){
            int z=nu[i];
            if((x[z]!=y[z])&&(x[z]!=x[nu[i-1]]||y[z]!=y[nu[i-1]]))
            addedge(x[z],y[z]),du[y[z]]++;
        }
    }
    void Reset()
    {
        for(int i=1;i<=col;i++)
        if(!du[i]){
            que[++w]=i;
            dis[i]=si[i];
            e[i]=1;
            if(dis[i]>dis[ans]) ans=i;
        }
    }
    void Topo()
    {
        while(t<w){
            int u=que[++t];
            for(int i=head[u];i;i=next[i]){
                int v=ver[i];
                --du[v];
                if(dis[v]<dis[u]+si[v]){
                    dis[v]=dis[u]+si[v];
                    e[v]=0;
                    if(dis[ans]<dis[v]) ans=v;
                }
                if(dis[v]==dis[u]+si[v]) e[v]=(e[v]+e[u])%MOD;
                if(!du[v]) que[++w]=v;
            }
        }
    }
    void ANS()
    {
        for(int i=1;i<=n;i++)
        if(dis[i]==dis[ans]) anss=(anss+e[i])%MOD;
    }
    int main(void)
    {
        int i,j;
        scanf("%d%d%d",&n,&m,&MOD);
        for(i=1;i<=m;i++){
            scanf("%d%d",&x[i],&y[i]);
            addedge(x[i],y[i]);
        }
        for(i=1;i<=n;i++)
        if(!num[i]) Tarjan(i);
        
        Remove();
        Build();
        Reset();
        Topo();
        ANS();
        printf("%d
    %d",dis[ans],anss);
        return 0;
    }
    View Code
  • 相关阅读:
    关于dva前后端分离的跨域问题
    十大经典排序算法
    Java并发编程核心概念一览
    StringBuilder线程为什么不安全
    Java序列化的10个问题
    10 个最难回答的 Java 问题
    lombok @EqualsAndHashCode 注解讲解
    内存泄漏和内存溢出的区别和联系
    RabbitMQ
    RabbitMQ原理图
  • 原文地址:https://www.cnblogs.com/2018zxy/p/10366708.html
Copyright © 2020-2023  润新知