HDU 3639 强连通加缩点

来源:互联网 发布:广州淘宝拍摄基地地址 编辑:程序博客网 时间:2024/04/30 04:45
///先瞎做一番试试,我的实力的确是应该好好涨涨了。//总算过了。。。#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<vector>#include<string>#define inf 0x3f3f3f3f#define maxn 100500using namespace std;int n;//n m 为点数和边数int sum;int head[maxn], edgenum;int minw[maxn];int DFN[maxn], Low[maxn], Stack[maxn], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)int taj;//连通分支标号,从1开始int Belong[maxn];//Belong[i] 表示i点属于的连通分支bool Instack[maxn];vector<int> bcc[maxn]; //标号从1开始bool vis[maxn];vector<int>G[maxn];int du[maxn];int gu[maxn];struct Edge{    int from, to, nex;    bool sign;//是否为桥}edge[60000];void addedge(int u, int v){//边的起点和终点    Edge E={u, v, head[u], false};    edge[edgenum] = E;    head[u] = edgenum++;}void tarjan(int u ,int fa)//求出图的强联通分量{    DFN[u] = Low[u] = ++ Time ;    Stack[top ++ ] = u ;    Instack[u] = 1 ;    for (int i = head[u] ; ~i ; i = edge[i].nex ){        int v = edge[i].to ;        if(DFN[v] == -1)        {            tarjan(v , u) ;            Low[u] = min(Low[u] ,Low[v]) ;            if(DFN[u] < Low[v])            {                edge[i].sign = 1;//为割桥            }        }        else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;    }    if(Low[u] == DFN[u]){        int now;        taj ++ ;bcc[taj].clear();        do{            now = Stack[-- top] ;            Instack[now] = 0 ;            Belong [now] = taj ;            bcc[taj].push_back(now);        }while(now != u) ;    }}void tarjan_init(int all){    memset(DFN, -1, sizeof(DFN));    memset(Instack, 0, sizeof(Instack));    top = Time = taj = 0;    for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!}void suodian()////还要更新出入度。。{    memset(du, 0, sizeof(du));    memset(gu,0,sizeof(gu));    memset(minw,0,sizeof(minw));    for(int i = 1; i <= taj; i++)G[i].clear();    for(int i = 0; i < edgenum; i++){        int u = Belong[edge[i].from], v = Belong[edge[i].to];        if(u!=v)G[v].push_back(u), du[u]++,gu[v]++;///g[u]存的是出度,du[v]存的是入度    }    for(int i=1;i<=n;i++)        minw[Belong[i]]++;}void init(){memset(head, -1, sizeof(head)); edgenum=0;}///遍历图、、建反向图然后深搜。。void dfs(int u)///入度为0的点。。{    vis[u]=true;    sum+=minw[u];    for(int i=0;i<G[u].size();i++)    {        if(!vis[G[u][i]])            dfs(G[u][i]);    }//反向建图是因为要找的是可到达该点的强连同分量。。}int allans[maxn];int TOT[maxn];void solve(){    memset(allans,0,sizeof(allans));    int maxx=0;int index=0;    for(int i=1;i<=taj;i++)    {        if(du[i]==0)        {            memset(vis,false,sizeof(vis));            sum=0;            dfs(i);            allans[i]=sum;            if(allans[i]>maxx)            {                index=i;                maxx=allans[i];            }        }    }     cout<<maxx-1<<endl;     int tot=0;//     cout<<taj<<" taj"<<endl;//     for(int i=1;i<=n;i++)//        cout<<Belong[i]<<endl;//     cout<<"测试。。。"<<endl;//     cout<<index<<endl;//     for(int i=1;i<=n;i++)//        if(Belong[i]==index)//        cout<<i<<" ";//     cout<<endl;//     cout<<"-----------------------------"<<endl;     for(int i=1;i<=n;i++)     {         if(allans[Belong[i]]==maxx)           TOT[++tot]=i;     }     for(int i=1;i<tot;i++)        cout<<TOT[i]-1<<" ";     cout<<TOT[tot]-1<<endl;}int  main(){//    freopen("inn.txt","r",stdin);    int cas,a,b;    scanf("%d",&cas);    int ca=0;    while(cas--)    {        ca++;        init();        int m;        scanf("%d%d",&n,&m);        while(m--)        {            scanf("%d%d",&a,&b);            a++,b++;            addedge(a,b);        }        tarjan_init(n);        suodian();       cout<<"Case "<<ca<<": ";       solve();    }}

0 0