3037: 创世纪
Description
applepi手里有一本书《创世纪》,里面记录了这样一个故事……
上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。
由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2^N) 级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。
Input
第一行是一个整数N,表示世界元素的数目。
第二行有 N 个整数A1, A2, …, AN。Ai 表示第i 个世界元素能够限制的世界元素的编号。
Output
一个整数,表示最多可以投放的世界元素的数目。
Sample Input
2 3 1 3 6 5
Sample Output
HINT
样例说明
选择2、3、5 三个世界元素即可。分别有1、4、6 来限制它们。
数据范围与约定
对于30% 的数据,N≤10。
对于60% 的数据, N≤10^5。
对于 100% 的数据,N≤10^6,1≤Ai≤N,Ai≠i。
Source
给定一张有向图,每个点有且仅有一条出边,要求若一个点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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }