创世纪 jzoj3929 bfs
程序员文章站
2023-12-24 21:01:33
...
Description
上帝手中有着n种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。
由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2^n)级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。
Input
第一行一个正整数n,表示世界元素的数目。
第二行n个正整数a_1, a_2, …, a_n。a_i表示第i个世界元素能够限制的世界元素的编号。
Output
最多可以投放的世界元素的数目。
Data Constraint
–
30%的数据,n<=10。
60%的数据,n<=10^5。
100%的数据,a_i<=n<=10^6
Solution
好久不做题了
很经典的套路,限制关系可以转为一张图。由于限制的性质我们可以知道这张图的任意一点出度为1且入度不一定为1,那么就是一个有向的、叶节点套着环、末尾两端套着环的链状图
大概这样
那么入度为0的点一定不能选,贪心地隔一个选取节点可以保证链上选取的点数量最多。对于一个有n个节点环我们最多可以取n/2个节点,并且这些节点的选取不会被链上的选取策略影响。实现就已经很明显了,bfs统计链,顺便统计每个环的大小
Code
#include <stdio.h>
#include <string.h>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define N 1200001
int tar[N], ind[N];
bool vis[N];
std:: queue<int> que;
int main(void){
int n;
scanf("%d", &n);
rep(i, 1, n){
scanf("%d", &tar[i]);
ind[tar[i]] += 1;
}
fill(vis, 0);
rep(i, 1, n){
if (!ind[i]){
que.push(i);
}
}
int ans = 0;
while (!que.empty()){
int now = que.front(); que.pop();
if (!vis[tar[now]] && !vis[now]){
vis[tar[now]] = 1;
ans += 1;
if (!(-- ind[tar[tar[now]]])){
que.push(tar[tar[now]]);
}
}
vis[now] = 1;
}
rep(i, 1, n){
if (!vis[i]){
vis[i] = 1;
int size = 1;
int now = i;
while (tar[now] != i && !vis[tar[now]]){
now = tar[now];
vis[now] = 1;
size += 1;
}
ans += size / 2;
}
}
printf("%d\n", ans);
return 0;
}