杀人游戏

题目描述
杀人游戏是一个在信息奥赛选手中流行的游戏,这个游戏不在结果,重在参与,就像信息奥赛一样。这个游戏的一方称为杀手,剩下的一方称为平民。杀手知道每个人的身份,但是平民不知道。在游戏过程中,平民的任务是找出谁是杀手。
游戏玩了若干轮,现在还剩下n个人,每个人都指认了一个杀手。,当然,平民基本是乱猜的,而杀手则全部指认的是平民。在不知道谁是杀手的情况下,最多可能有多少杀手。

输入
输入格式:
第一行包含一个整数N(2<=N<=500000),表示还有n个人。这n个人标号为1到n。
接下来有n行,每行一个数,其中的第k行表示被第k个人指认为杀手的人。
没有谁会指认自己为杀手。
输出
一个整数,表示最多可能的杀手的数量。

样例输入
3
2
1
1

样例输出
2

一个伪森林。由于一个点只能指向另一个点,所以一个连通分量里最多有一个环。
有一个贪心算法,对于每个连通分量,找到所有入度为0的点,视为杀手,它们所指向的点就为平民。
删掉杀手点和平民点,其他点的入度相应改变。再重复这个操作多次。  
最后只会剩下一个环。将环中的任一点视为平民(这并不影响),然后删掉这个点,环变成链,继续上面的操作就可以了。
#include<cstdio>
#define MAXN 500000

struct node{
    int v;
    node *next;
}edge[MAXN+10],*adj[MAXN+10],*ecnt=&edge[0];

int n,inp[MAXN+10],son[MAXN+10],ans;
bool vis[MAXN+10];
void read()
{
    int x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        son[i]=x;
        inp[x]++;
    }
}
void dfs(int u,int d)
{
    if(vis[u]) return ;
    vis[u]=true;
    ans+=d;
    if(--inp[son[u]]==0 || d==1)
        dfs(son[u],1-d);
}
void workout()
{
    for(int i=1;i<=n;i++)
        if(!inp[i])
            dfs(i,1);
    for(int i=1;i<=n;i++)
        dfs(i,0);
    printf("%d\n",ans);
}
int main()
{
    read();
    workout();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值