博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[POI 2004]SZP
阅读量:5794 次
发布时间:2019-06-18

本文共 2181 字,大约阅读时间需要 7 分钟。

[POI 2004]SZP

Description

Byteotian 中央情报局 (BIA) 雇佣了许多特工他们每个人的工作就是监视另一名特工.

Byteasar 国王需要进行一次秘密行动,所以他要挑选尽量多的信得过的特工但是这项任务是如此的机密以至于所有参加行动的特工都必须至少被另一名没有参加任务的特工所监视(就是说如果某个特工参加了行动,那么原先监视他的那些特工中至少要有一个没有参加进行动). 给出监视任务的详情,要求计算最多能有多少个特工参与其中

Input

第一行只有一个整数, n – 特工的总数, 2 <= n <= 1000000. 特工从 到 编号接下来 n行每行一个整数 ak 表示特工 将要监视特工 ak , 1 <= k <= n, 1 <= ak <= n, ak <> k. 

Output

打印一个数,最多能有多少特工参加入这个任务

Sample Input

6

2

3

1

3

6

Sample Output

HINT

题解

可以用贪心+拓扑排序做。

首先我们可以发现,入度为0的点必然不能被选,我们先将所有点标记为不选,将入度为0的点加入队列中。

由贪心的思想,我们为了被选的点更多,我们要将不选的点所指向的点选上。

证明:若点i确定为不选,若ak[i]不选也只能提供一个点被选(ak[i]指向的点),故ak[i]选上不会差。

若所有指向i的点均选,则i只能是不选。

由于图可能不连通还可能有环。我们只需要最后剩下的环从任意处切开即可。

由于我们在拓扑排序的过程中在环上做过标记。我们只要考虑没做过标记的一段,即有i标记为不选,ak[i]标记也为不选,显然我们要标记ak[i]为选。

#include
#include
#include
#include
#include
#include
#include
using namespace std;int n,m,ans;int gi(){ int ans=0,f=1;char i=getchar(); while(i<'0'||i>'9'){ if(i=='-')f=-1;i=getchar();} while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} return ans*f;}struct node{ int next,to;}edge[1000005];int head[1000005],size=1,in[1000005],cnt[1000005],to[1000005];void putin(int from,int to){ size++; edge[size].next=head[from]; edge[size].to=to; head[from]=size;}void bfs(){ queue
mem; int i,j; for(i=1;i<=n;i++) if(!in[i])mem.push(i); while(!mem.empty()) { int x=mem.front();mem.pop(); if(!cnt[x]) { for(i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if(in[y]) { cnt[y]++; in[y]--; if(!in[y])mem.push(y); } } } else { ans++; for(i=head[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if(in[y]) { in[y]--; if(!in[y])mem.push(y); } } } }}void find(int r){ int i;in[r]=0; if(cnt[r])ans++; if(cnt[to[r]])ans++; if(!cnt[r]&&!cnt[to[r]]) { ans++; cnt[to[r]]++; } for(i=to[r];to[i]!=r;i=to[i]) { if(!cnt[i]&&!cnt[to[i]]) { ans++; cnt[to[i]]++; } else if(cnt[to[i]])ans++; in[i]=0; } in[i]=0;}int main(){ memset(head,-1,sizeof(head)); int i,j; n=gi(); for(i=1;i<=n;i++) { j=gi(); putin(i,j); to[i]=j; in[j]++; } bfs(); for(i=1;i<=n;i++) if(in[i])find(i); printf("%d",ans); return 0;}

 

转载于:https://www.cnblogs.com/huangdalaofighting/p/7423514.html

你可能感兴趣的文章
H. 硬币的水问题II
查看>>
Async Console Programs 异步控制台程序
查看>>
持续集成之hudson的构建任务调度
查看>>
Android消息通知
查看>>
WebApi系列~StringContent与FormUrlEncodedContent
查看>>
Windows 8.1 新增控件之 CommandBar
查看>>
基于jQuery UI Autocomplete的AngularJS 指令(directive)扩展
查看>>
状态模式(Strategy Pattern)
查看>>
Windows 7 任务栏开发 之 跳转列表(Jump Lists)
查看>>
29.4. ldd - print shared library dependencies
查看>>
PostgreSQL在何处处理 sql查询之四十六
查看>>
使用Zabbix服务端本地邮箱账号发送报警邮件及指定报警邮件操作记录
查看>>
[CSS]Web前端开发之CSS工具列表
查看>>
PostgreSQL的autovacuum 与 vacuum full
查看>>
微软开源分布式高性能GB框架LightGBM Ubuntu、CentOS下编译安装过程
查看>>
Linux 源码安装httpd
查看>>
CentOS7.3安装LAMP(Centos7.3+Apache2.4.6+mysql5.6.38+php5.4.16)
查看>>
第 1 章 Nginx
查看>>
OK335xS canutils deal with compile error
查看>>
Redis数据结构详解之List(二)
查看>>