[HAOI2006]受欢迎的牛

https://www.lydsy.com/JudgeOnline/problem.php?id=1051

https://www.luogu.org/problemnew/show/P2341

题意:算出有多少头奶牛可以当明星。

题解:强连通分量

由题可得,受欢迎的奶牛只有可能是图中唯一的出度为零的强连通分量中的所有奶牛,所以若出现两个以上出度为0的强连通分量则不存在明星奶牛,因为那几个出度为零的分量的爱慕无法传递出去。那唯一的分量能受到其他分量的爱慕同时在分量内相互传递,所以该分量中的所有奶牛都是明星。

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,p,l,r,u,v;
int ans,cnt,flag,temp,sum,top,col;
int a,b,c,sta[N],vis[N],low[N],dfn[N],si[N],co[N],de[N];
vector<int>G[N];
void Tarjan(int u){
    dfn[u]=low[u]=++sum;
    vis[u]=1;
    sta[++top]=u;
    for(int i=0,j=G[u].size();i<j;i++){
        int v=G[u][i];
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[v],low[u]);
        }else if(vis[v]){
            low[u]=min(dfn[v],low[u]);
        }
    }
    if(dfn[u]==low[u]){
        co[u]=++col;
        ++si[col];
        while(sta[top]!=u){
            ++si[col];
            co[sta[top]]=col;
            vis[sta[top]]=0;
            --top;
        }
        vis[sta[top]]=0;
        --top;
    }

}
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        G[b].push_back(a);
    }
    for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
    for(int i=1;i<=n;i++)
        for(int j=0,k=G[i].size();j<k;j++)
            if(co[i]!=co[G[i][j]])
                de[co[G[i][j]]]++;
    for(int i=1;i<=col;i++)if(!de[i])ans=si[i],cnt++;
    cout<<(cnt==1?ans:0)<<endl;
    //}

#ifdef DEBUG
	printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

C++版本二

题解:kosaraju算法

一个反图,从最后那个强连通分量中随便找一个点,然后进行反图遍历

如果所有的点都被访问过了,证明最后一个强连通分量中的点都是明星牛,如果访问不到,则说明没有牛是明星

#include <bits/stdc++.h>
using namespace std;
#define maxn 10010
int m,n,nl,mmp,sum;
vector<int> G[maxn];
vector<int> RG[maxn];
vector<int> vs;
bool used[maxn];
int cmp[maxn];
void add(int a,int b)//两个邻接表存储 
{
    G[a].push_back(b);//正图 
    RG[b].push_back(a);//反图 
}
void dfs(int v)//第一遍搜索; 
{
    used[v]=1;
    for(int i=0;i<G[v].size();i++)
    {
        if(!used[G[v][i]])
        dfs(G[v][i]);
    }
    vs.push_back(v);
}
void rdfs(int v,int k)//第二遍搜索 
{
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<RG[v].size();i++)
    {
        if(!used[RG[v][i]])
        rdfs(RG[v][i],k);
    }
}
int scc()
{
    memset(used,0,sizeof(used));
    vs.clear();
    for(int i=1;i<=n;i++)
    if(!used[i])
    dfs(i);
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--)
    if(!used[vs[i]])
    rdfs(vs[i],k++);
    return k;
}
int DFS(int haha)//其实这个搜索可以直接用第二个(rdfs)替代,不过这样看起来比较清楚。。。。。。 
{
    used[haha]=1;
    for(int i=0;i<RG[haha].size();i++)
    {
        if(!used[RG[haha][i]])
        DFS(RG[haha][i]);
    }
}
int main()
{
    int u,p;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    cin>>u>>p,add(u,p);
    int ans=scc();
    //cout<<ans<<endl;
    for(int i=1;i<=n;i++)
    {
    if(cmp[i]==ans-1)//注意这里ans要减一; 
        {
            mmp=i;
            sum++;
        }
    }
    memset(used,0,sizeof(used));
    rdfs(mmp,1);
    for(int i=1;i<=n;i++)//看一下是否所有点都被访问过了 
    {
        if(!used[i])
        {
            cout<<0<<endl;
            return 0;
        }
    }
    cout<<sum<<endl;//如果都被访问过了则最后一个强连通分量里的牛牛都是明星,输出即可; 
    return 0;
}

 

全部评论

相关推荐

听说改名字就能收到offer哈:Radis写错了兄弟
点赞 评论 收藏
分享
面试摇了我吧:啊哈哈面试提前五个小时发,点击不能参加就是放弃
点赞 评论 收藏
分享
评论
点赞
收藏
分享
正在热议
# 25届秋招总结 #
443603次浏览 4524人参与
# 春招别灰心,我们一人来一句鼓励 #
42308次浏览 539人参与
# 阿里云管培生offer #
120503次浏览 2222人参与
# 地方国企笔面经互助 #
7978次浏览 18人参与
# 同bg的你秋招战况如何? #
77334次浏览 569人参与
# 实习必须要去大厂吗? #
55824次浏览 961人参与
# 北方华创开奖 #
107485次浏览 600人参与
# 虾皮求职进展汇总 #
116484次浏览 887人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11711次浏览 292人参与
# 实习,投递多份简历没人回复怎么办 #
2455078次浏览 34862人参与
# 提前批简历挂麻了怎么办 #
149970次浏览 1979人参与
# 在找工作求抱抱 #
906139次浏览 9423人参与
# 如果公司给你放一天假,你会怎么度过? #
4764次浏览 55人参与
# 你投递的公司有几家约面了? #
33209次浏览 188人参与
# 投递实习岗位前的准备 #
1196082次浏览 18551人参与
# 机械人春招想让哪家公司来捞你? #
157650次浏览 2267人参与
# 双非本科求职如何逆袭 #
662415次浏览 7397人参与
# 发工资后,你做的第一件事是什么 #
12811次浏览 62人参与
# 工作中,努力重要还是选择重要? #
35944次浏览 384人参与
# 简历中的项目经历要怎么写? #
86956次浏览 1517人参与
# 参加完秋招的机械人,还参加春招吗? #
20156次浏览 240人参与
# 我的上岸简历长这样 #
452084次浏览 8089人参与
牛客网
牛客企业服务