HDU3639 Hawk-and-Chicken (强联通分量+scc缩点+反向建图)

题目链接HDU3639

在这里插入图片描述
在这里插入图片描述
题目大意:
N个小朋友有M组单向关系,现在询问一个小朋友能得到的最多支持有多少,输出这个最大值和这些小朋友的编号。
问题分析:

其实就是,一个点的贡献等于能到达它的点的个数。求这个最大贡献并且输出所有满足条件的点编号。考虑到有向图中的一个环相互传递,先dcc缩点后形成若干个点,由于前面的边的单向关系,导致我们要算贡献的那个缩点的出度必定是0。因此直接对缩点后的图反向建图,入度为0的点就是可能的答案,以它为起点计算它能经过图中的点权和,注意搜索时打上标记 。

#include<bits/stdc++.h>
#include<cstring>
#include<cstdio>
#include<queue>
#define Re register int
using namespace std;
const int N=5e4+300,M=1e5+3;
int n,m,x,y,Q_o,ans,A[N],ru[N],gs[N],ip[N],dp[N],cu[N],flag[N];
inline void in(Re &x)
{
    int f=0;
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
vector<int>dcc[N];
inline int min(Re a,Re b)
{
    return a<b?a:b;
}
inline int max(Re a,Re b)
{
    return a>b?a:b;
}
struct Tarjan
{
    int o,t,dfn_o,Q[N],low[N],dfn[N],pan[N],head[N];
    struct QAQ
    {
        int x,to,next;
    } a[M];
    inline void add(Re x,Re y)
    {
        a[++o].x=x,a[o].to=y,a[o].next=head[x],head[x]=o;
    }
    inline void cle()
    {
        memset(head,0,sizeof(head));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(gs,0,sizeof(gs));
        memset(ip,0,sizeof(ip));
        memset(pan,0,sizeof(pan));
        dfn_o=t=o=0;
        Q_o=0;

    }
    inline void tarjan(Re x)
    {
        dfn[x]=low[x]=++dfn_o,Q[++t]=x,pan[x]=1;
        for(Re i=head[x],to; i; i=a[i].next)
            if(!dfn[to=a[i].to])
                tarjan(to),low[x]=min(low[x],low[to]);
            else if(pan[to])
                low[x]=min(low[x],dfn[to]);
        if(low[x]==dfn[x])
        {
            ++Q_o;
            while(1)
            {
                dcc[Q_o].push_back(Q[t]);
                ip[Q[t]]=Q_o,gs[Q_o]+=A[Q[t]],pan[Q[t]]=0;
                if(x==Q[t--])
                    break;
            }

        }
    }
    inline void SuoPoint()
    {
        for(Re i=1; i<=n; ++i)
            if(!dfn[i])
                tarjan(i);
    }
} T1;
struct Tuopu
{
    int o,pan[N],head[N];
    std::queue<int>Q;
    struct QAQ
    {
        int to,next;
    } a[M<<1];
    inline void add(Re x,Re y)
    {
        a[++o].to=y,a[o].next=head[x],head[x]=o;
    }
    inline void cle()
    {
        memset(head,0,sizeof(head));
        memset(dp,0,sizeof(dp));
        o=0;
        memset(ru,0,sizeof(ru));
        memset(cu,0,sizeof(cu));

    }
    inline int dfs(Re rt)
    {
        int add=0;
        flag[rt]=1;
        for(int i=head[rt]; i; i=a[i].next)
        {
            if(!flag[a[i].to])
            {
                flag[a[i].to]=1;
                add=add+gs[a[i].to]+dfs(a[i].to);
            }

        }
        return add;
    }
    inline void creat()
    {
        for(Re i=1; i<=T1.o; ++i)
            if((x=ip[T1.a[i].x])!=(y=ip[T1.a[i].to]))
            {
                ++ru[x],add(y,x),++cu[y];
            }
    }
    inline void tuopu()
    {
        for(Re i=1; i<=Q_o; ++i)
            if(!ru[i])
                dp[i]=gs[i],Q.push(i);
        while(!Q.empty())
        {
            Re x=Q.front();
            Q.pop();
            for(Re i=head[x],to; i; i=a[i].next)
            {
                to=a[i].to;
                dp[to]=max(dp[to],dp[x]+gs[to]);
                if(!(--ru[to]))
                    Q.push(to);
            }
        }
    }
} T2;
vector<int>anss;
vector<int>ap;
int main()
{
    Re cases=0;
    in(cases);
    Re ca=0;
    while(cases--)
    {
        in(n),in(m);
        ca++;
        for(Re i=1; i<=n; ++i)
            A[i]=1;
        T1.cle();
        T2.cle();
        while(m--)
            in(x),in(y),T1.add(x+1,y+1);

        T1.SuoPoint();
        T2.creat();
        int sum=0;
        for(int i=1; i<=Q_o; i++)
        {
            if(!ru[i])
            {
                memset(flag,0,sizeof(flag));

                int fuck= T2.dfs(i)+gs[i]-1;

                if(fuck>sum)
                {
                    sum=fuck;
                    anss.clear();
                    anss.push_back(i);
                    continue;
                }
                if(fuck==sum)
                {
                    anss.push_back(i);
                }
            }

        }
        printf("Case %d: %d\n",ca,sum);

        for(int i=0; i<anss.size(); i++)
        {

            for(int j=0; j<dcc[anss[i]].size(); j++)
            {
                ap.push_back(dcc[anss[i]][j]-1);
            }

        }
        sort(ap.begin(),ap.end());
        for(int i=0; i<ap.size(); i++)
        {
            printf("%d",ap[i]);
            if(i!=ap.size()-1)
                printf(" ");
        }

        ap.clear();
        anss.clear();
        for(int i=1; i<=Q_o; i++)
        {
            dcc[i].clear();
        }
        printf("\n");

    }
}


提供一组特例
6 6 N M
0 1
0 2
1 5
1 3
2 3
2 4
反向建图后在这里插入图片描述
答案应该为 3 3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值