hdu3639

题目大意简单:注意,如果1->2,2->3,3->1,,则最大支持为2,

运行tarjan将强连通分量缩点,形成一个DAG,  对DAG建立反图,那么为入度为0的点,才可能为有最大支持量(或正向建图,出度为0的点),所以对入度为0的点bfs即可求出最大的支持量,有些细节要注意具体见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct node
{
    int u,v;
};
node e[40000];
int first[5005],next[40000];
int dfn[5005],low[5005],flag[5005],stack[5005];
int cc,time,top,sum;
int num[5005],vis[5005];
int first1[5005],next1[40000],inde[5005];
node e1[40000];
int temp[5004];
inline void add_edge(int u,int v)
{
    e[cc].u=u;
    e[cc].v=v;
    next[cc]=first[u];
    first[u]=cc;
    cc++;
}
inline void add_edge1(int u,int v)
{
    e1[cc].u=u;
    e1[cc].v=v;
    next1[cc]=first1[u];
    first1[u]=cc;
    cc++;
}
int tardfs(int s)
{
    flag[s]=1;
    stack[++top]=s;
    low[s]=dfn[s]=time++;
    int i;
    for(i=first[s];i!=-1;i=next[i])
    {
        int v=e[i].v;
        if(flag[v]==0)
            tardfs(v);
        if(flag[v]==1)
            low[s]=min(low[s],low[v]);
    }
    if(low[s]==dfn[s])
    {
        sum++;
        do
        {
            low[stack[top]]=sum;
            flag[stack[top]]=2;
            num[sum]++;
        }while(stack[top--]!=s);
    }
    return 0;
}
int tarjan(int n)
{
    memset(flag,0,sizeof(flag));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(num,0,sizeof(num));
    int i;
    time =1;
    top=0;
    sum=0;
    for(i=0;i<n;i++)
    {
        if(flag[i]==0)
            tardfs(i);
    }
    return 0;
}
int bfs(int i)
{
    queue<int> q;
    int sum=num[i]-1;
    q.push(i);
    memset(vis,0,sizeof(vis));
    vis[i]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        int j;
        for(j=first1[u];j!=-1;j=next1[j])
        {
            if(!vis[e1[j].v])
            {
                vis[e1[j].v]=1;
                sum+=num[e1[j].v];
                q.push(e1[j].v);
            }
        }
    }
    return sum;
}
int main()
{
    int tt,cas;
    scanf("%d",&tt);
    for(cas=1;cas<=tt;cas++)
    {
        memset(first,-1,sizeof(first));
        memset(next,-1,sizeof(next));
        int n,m;
        scanf("%d%d",&n,&m);
        int i;
        cc=0;
        for(i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        tarjan(n);
        cc=0;
        memset(first1,-1,sizeof(first1));
        memset(next1,-1,sizeof(next1));
        memset(inde,0,sizeof(inde));
        for(i=0;i<n;i++)
        {
            int j;
            for(j=first[i];j!=-1;j=next[j])
                if(low[e[j].u]!=low[e[j].v])
                {
                    add_edge1(low[e[j].v],low[e[j].u]);
                    inde[low[e[j].u]]++;
                }
        }
        int res=0;
        memset(temp,0,sizeof(temp));
        for(i=1;i<=sum;i++)
        {
            if(inde[i]==0)
            {
                int ans=bfs(i);
                temp[i]=ans;
                if(ans>res)
                {
                    res=ans;
                }
            }
        }
        printf("Case %d: %d\n",cas,res);
        int ff=0;
        for(i=0;i<n;i++)
        {
            if(temp[low[i]]==res)
            {
                if(ff==0)
                    printf("%d",i),ff=1;
                else
                    printf(" %d",i);
            }
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值