创世纪【解题报告】

Description

applepi手里有一本书《创世纪》,里面记录了这样一个故事……
上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。
由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2^N) 级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。

Input

第一行是一个整数N,表示世界元素的数目。
第二行有 N 个整数A1, A2, …, AN。Ai 表示第i 个世界元素能够限制的世界元素的编号。

Output

一个整数,表示最多可以投放的世界元素的数目。

Sample Input

6
2 3 1 3 6 5

Sample Output

3

HINT

 

样例说明

选择2、3、5 三个世界元素即可。分别有1、4、6 来限制它们。


数据范围与约定

对于30% 的数据,N≤10。

对于60% 的数据, N≤10^5。

对于 100% 的数据,N≤10^6,1≤Ai≤N,Ai≠i。

 
 
 
好像有树形dp的解法,但我只写了贪心。
一句话概括的话:从入度为0的点开始按拓扑深度分层,每一层的元素个数总是不增的,于是当前层能选则选。(我不知道用词对不对qwq)
大概就是入度为0的点,我必须留下,而他连接的点,如果没有被要求必须留下,那么他就丢掉,最终会剩下若干个环,环的情况我们
只需要留下一半的元素即可(模拟很容易发现)。
至于证明,可以用上面说的“不增”来理解。
也可以“反证”,假设1入度为0,那么1留下,1指向2,那么2丢弃,如果不丢2,那么我们可以选择丢2指向的3,但这样肯定不会更优,因为还可能有别的指向3,因为每个点(比如2)只会引出一条边,如果这个点不选,那他带来的收益也就是他指向的点可以选上了,而他指向的点还有可能被别的点所指向,也就是说尽管我丢掉了当前点,我指向的点依然可能被丢掉,那么这样贡献是2(或者1),而不丢掉当前点的贡献是1,保证不会更优,所以贪心正确。
 
附上代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,a[1000006],in[1000006],vis[1000006];
 4 queue<int>S;
 5 int main()
 6 {
 7     scanf("%d",&n);
 8     for(int i=1;i<=n;i++)scanf("%d",&a[i]),in[a[i]]++;
 9     for(int i=1;i<=n;i++){
10         if(!in[i]){
11             S.push(i);
12             vis[i]=1;
13         }
14     }
15     int ans=0;
16     while(!S.empty()){
17         int u=S.front();
18         S.pop();
19         if(!vis[a[u]]){
20             vis[a[u]]=2;
21             ans++;
22             in[a[a[u]]]--;
23             if(!in[a[a[u]]]){
24                 S.push(a[a[u]]);
25                 vis[a[a[u]]]=1;
26             }
27         }
28     }
29     for(int i=1;i<=n;i++){
30         if(vis[i])continue;
31         int cnt=0,now=i;
32         while(!vis[now]){
33             vis[now]=1;
34             cnt++;
35             now=a[now];
36         }
37         ans+=cnt/2;
38     }
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/7805730.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值