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\n%d",dis[ans],anss);
    return 0;
}
View Code

 

posted @ 2019-02-12 18:48  麟阁  阅读(219)  评论(0编辑  收藏  举报