codevs1919创世纪
1919 创世纪
时间限制: 2 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述 Description
上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2N) 级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。
输入描述 Input Description
第一行是一个整数N,表示世界元素的数目。
第二行有 N 个整数A1, A2, …, AN。Ai 表示第i 个世界元素能够限制的世界元素的编号。
输出描述 Output Description
一个整数,表示最多可以投放的世界元素的数目。
样例输入 Sample Input
6
2 3 1 3 6 5
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
选择2、3、5 三个世界元素即可。分别有1、4、6 来限制它们。
对于 30% 的数据,N≤10。
对于 100% 的数据,N≤106,1≤Ai≤N,不保证Ai≠i。
来源:Nescafe VIII
标签上写着树形dp,但是瞎搞搞居然就。。。神了。。。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxn 10000003 using namespace std; bool vis[maxn]; queue<int> q; int val[maxn],n,rnk[maxn],ans; int find(int x) { int ret=0; while(!vis[x]) { ret++; vis[x]=1; x=val[x]; } return ret; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&val[i]); ++rnk[val[i]]; } for(int i=1;i<=n;++i) if(!rnk[i]) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); if(vis[val[u]]) continue; ans++; vis[val[u]]=1; if(--rnk[val[val[u]]]==0&&!vis[val[val[u]]]) q.push(val[val[u]]); } for(int i=1;i<=n;++i) if(!vis[i]) ans+=find(i)/2; printf("%d",ans); return 0; }
大概是拓扑排序的样子。。