3037: 创世纪

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。


 

 

Source

 
 
看的第一眼以为和1040骑士是一个套路。。。然后就改了改代码交了上去。。。结果就WA了个爽。。。
然后想一下。。。其实还是有些区别的。。。这道题的限制只有一个。。。
搬运题解:

给定一张有向图,每个点有且仅有一条出边,要求若一个点x扔下去,至少存在一个保留的点y,y的出边指向x,求最多扔下去多少个点

首先原题的意思就是支配关系 我们反向考虑 求最少保留的点 要求一个点若扔出去 则必须存在一个保留的点指向它

于是这就是最小支配集 不过由于是有向图 所以一个点要么选择 要么被子节点支配 所以就只剩下2个状态了

设f[x]为以x为根的子树选择x的最小支配集 g[x]为不选择x的最小支配集

然后由于是基环树林 所以我们选择一个环上的点 拆掉它的出边 设这个点为x 出边指向的点为y 讨论

1.若x选择 则y一开始就是被支配状态 g[y]初值为0 求一遍最小支配集

2.若x不选 正常求最小支配集即可

两种情况取最小值计入ans 最后输出n-ans即可

http://blog.csdn.net/popoqqq/article/details/39965603

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define inf 1000000000
13 #define maxn 1000005
14 #define maxm 1000005
15 #define eps 1e-10
16 #define ll long long
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
22 using namespace std;
23 struct edge{
24     int go,next;bool ban;
25 }e[maxm*2];
26 int head[maxn],tot;
27 int n,a[maxn],v[maxn],U;
28 int f[maxn],g[maxn],fa[maxn],ans,ban;
29 int read(){
30     int x=0,f=1;char ch=getchar();
31     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
32     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
33     return x*f;
34 }
35 void insert(int u,int v){
36     e[++tot].go=v;e[tot].next=head[u];head[u]=tot;
37 }
38 void dfs(int x){
39     v[x]=1;
40     if(v[a[x]]) U=x;
41     else dfs(a[x]);
42 }
43 void treeDP(int x){
44     f[x]=1;
45     g[x]=inf;
46     v[x]=1;
47     if(x==ban)g[x]=0;
48     for4(i,x){
49         if(i!=U&&y!=fa[x]){
50             fa[y]=x;
51             treeDP(y);
52             g[x]+=min(g[y],f[y]);
53             g[x]=min(g[x],f[x]+f[y]-1);
54             f[x]+=min(f[y],g[y]);
55         }
56     }
57 }
58 int main(){
59     //freopen("input.txt","r",stdin);
60     //freopen("output.txt","w",stdout);
61     n=read();
62     for1(i,n){
63         a[i]=read();
64         insert(a[i],i);
65     }
66     for1(i,n)
67         if(!v[i]){
68             dfs(i);
69             ban=a[U];
70             treeDP(U);
71             int tmp=f[U];
72             ban=0;
73             treeDP(U);
74             ans+=min(tmp,g[U]);
75         }
76     cout<<n-ans<<endl;
77     return 0;
78 }
View Code

 

posted @ 2016-05-18 10:45  HTWX  阅读(240)  评论(0编辑  收藏  举报