创世纪
Posted sydevil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创世纪相关的知识,希望对你有一定的参考价值。
创世纪
题目描述
applepi手里有一本书《创世纪》,里面记录了这样一个故事……
上帝手中有着(N)种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。
由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会(O(2^N))级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。输入格式
第一行是一个整数(N),表示世界元素的数目。
第二行有(N)个整数(A_1, A_2, …, A_N.A_i)表示第(i)个世界元素能够限制的世界元素的编号。输出格式
一个整数,表示最多可以投放的世界元素的数目。
样例输入
6
2 3 1 3 6 5样例输出
3
数据范围与约定
对于(100%)的数据,(N≤10^6,1≤Ai≤N,Ai≠i)。
思路:
先建树,发现是基环树森林,先固定各环上(1)点,再(dp2)次
(mathfrak{Talk is cheap,show you the code.})
#include<cstdio>
#include<set>
#include<bitset>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
# define ll long long
# define read read1<int>()
# define Type template<typename T>
Type inline const T read1(){
T m=0;
char k=getchar();
while((‘0‘>k||k>‘9‘)&&(k!=‘-‘))k=getchar();
const bool f=(k==‘-‘?1:0);
if(f)k=getchar();
while(‘0‘<=k&&k<=‘9‘)m=(m<<3)+(m<<1)+(k^48),k=getchar();
return f?-m:m;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define ll long long
# define N 1000000
int s,fa[N|1],Top,Beg,ty,ans,dp[N|1][2];
bool vis[N|1];
vector<int>G[N|1];
class Set{
int fa[N|1];
public:
int Find(int x){
if(x!=fa[x])fa[x]=Find(fa[x]);
return fa[x];
}
void clear(int n){for(int i=1;i<=n;++i)fa[i]=i;}
bool Union(int u,int v){
int x=Find(v);
if(x==u)return 1;
fa[u]=x;
return 0;
}
}w;
set<int>se,en;
void dfs(int n){
int tm=(en.count(n)&&ty)?0:1000001,tem=0;
for(int i=0;i<G[n].size();++i){
dfs(G[n][i]);
tm=min(tm,dp[G[n][i]][1]-min(dp[G[n][i]][1],dp[G[n][i]][0]));
tem+=min(dp[G[n][i]][1],dp[G[n][i]][0]);
}
dp[n][1]=tem+1;
dp[n][0]=tem+tm;
if(se.count(n))dp[n][!ty]=1000001;
}
int main(){
s=read;
w.clear(s);
for(int i=1;i<=s;++i)
if(w.Union(i,fa[i]=read))
se.insert(i),en.insert(fa[i]);
else G[fa[i]].push_back(i);
for(int i=1;i<=s;++i)
if(!vis[w.Find(i)]){
vis[w.Find(i)]=1;
int tans;
ty=0;dfs(w.Find(i));tans=min(dp[w.Find(i)][0],dp[w.Find(i)][1]);
ty=1;dfs(w.Find(i));tans=min(tans,min(dp[w.Find(i)][0],dp[w.Find(i)][1]));
ans+=tans;
}
printf("%d",s-ans);
return 0;
}
以上是关于创世纪的主要内容,如果未能解决你的问题,请参考以下文章