BZOJ1093 ZJOI2007 最大半连通子图 拓扑排序+连通性

题意:求一张图的最长链

题解:Tarjan缩点,拓扑排序求最长链,每个点的权值为该点在原图中所包含的点的数量。注意重构图后会有重边影响方案数。

#include <stack>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=100000+2;
const int MAXM=1000000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}*table[MAXN],*node[MAXN],mem[MAXM*2];
int N,M,X,cnt,ans,ans_sum,t[MAXN],c[MAXN],f[MAXN],d[MAXN],sum[MAXN],mark[MAXN];
int dfn[MAXN],low[MAXN],scc,depth;
bool flag[MAXN];
stack<int> s;
queue<int> q;

void Insert1(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));}

void Insert2(int u,int v){ node[u]=&(mem[cnt++]=HASH(v,node[u])),d[v]++;}

void Tarjan(int x){
    dfn[x]=low[x]=++depth,flag[x]=1,s.push(x);
    for(HASH *p=table[x];p;p=p->next)
        if(!dfn[p->u]) Tarjan(p->u),low[x]=min(low[x],low[p->u]);
        else if(flag[p->u]) low[x]=min(low[x],dfn[p->u]);

    if(dfn[x]==low[x]){
        int t=-1;scc++;
        while(t!=x){
            t=s.top(),s.pop();
            f[t]=scc,flag[t]=0,c[scc]++;
        }
    }
}

void Topological_Sort(){
    for(int i=1;i<=scc;i++)
        if(!d[i]) q.push(i),t[i]=c[i],sum[i]=1;

    int x;
    while(!q.empty()){
        x=q.front(),q.pop();
        for(HASH *p=node[x];p;p=p->next){
            d[p->u]--;
            if(!d[p->u]) q.push(p->u);

            if(mark[p->u]==x) continue;
            if(t[p->u]<t[x]+c[p->u]) t[p->u]=t[x]+c[p->u],sum[p->u]=sum[x];
            else if(t[p->u]==t[x]+c[p->u]) sum[p->u]=(sum[p->u]+sum[x])%X;
            mark[p->u]=x;
        }
    }
}

int main(){
    scanf("%d %d %d",&N,&M,&X);
    for(int i=1,u,v;i<=M;i++){
        scanf("%d %d",&u,&v);
        Insert1(u,v);
    }

    for(int i=1;i<=N;i++)
        if(!dfn[i]) Tarjan(i);
    for(int i=1;i<=N;i++)
        for(HASH *p=table[i];p;p=p->next)
            if(f[i]!=f[p->u]) Insert2(f[i],f[p->u]);

    Topological_Sort();
    for(int i=1;i<=scc;i++)
        if(ans<t[i]) ans=t[i],ans_sum=sum[i];
        else if(ans==t[i]) ans_sum=(ans_sum+sum[i])%X;
    printf("%d\n%d\n",ans,ans_sum);

    return 0;
}
View Code

 

posted @ 2017-02-28 00:10  WDZRMPCBIT  阅读(...)  评论(...编辑  收藏