CCC 2011 J5 Unfriend 题解

题面

题目传送门(题目在第10页)
Problem Description
Mark invited some people to join his social network. Some of them invited new people, who
invited new people, and so on. Now there are N N N people in the network, numbered from 1 1 1 to N N N .
Mark has decided to remove some people and keep others. There is one restriction: when removing
a person, he will also remove the people s/he invited, and the people they invited, and so on. Mark
will never remove himself, and we do not allow people to be invited by more than one person.
Mark can also decide to not remove anyone.
How many different sets of people can be removed?
Input Specification:
The first line contains a single integer N N N ( N ≤ 6 N ≤ 6 N6 ), the number of people in the network. Next are
N − 1 N − 1 N1 lines telling us who invited each person. To be precise, line i in this set ( 1 ≤ i ≤ N − 1 1 ≤ i ≤ N − 1 1iN1 )
contains a single integer j j j (with j > i j > i j>i ), which indicates that person j j j is the person who invited
person i i i. Person N N N is Mark.
Output Specification:
Output a single integer, the number of possible sets of people that can be removed.
Sample Input 1

3
3
3

Output for Sample Input 1
4
Explanation for Sample 1
The first number of the input indicates there are three people in the network. The next line tells
us that Person 1 was invited by Mark, while the last line tells us that Person 2 was also invited by
Mark. The sets of people that can be removed are { } \{\} { }, { 1 } \{1\} { 1}, { 2 } \{2\} { 2}, { 1 , 2 } \{1,2\} { 1,2} .
Sample Input 2
4 3 4 4
Output for Sample Input 2
6 10
Explanation for Sample 2
There are 4 4 4 people in the network. Here is a table of who invited who:

Person inviting Invited
1 1 1 none
2 2 2 none
3 3 3 1 1 1
4 4 4 2 , 3 2,3 2,3

The possible sets are { } \{\} { }, { 1 } \{1\} { 1}, { 2 } \{2\} { 2}, { 1 , 2 } \{1,2\} { 1,2} , { 1 , 3 } \{1,3\} { 1,3} , and { 1 , 2 , 3 } \{1,2,3\} { 1,2,3} . Notice that the sets { 3 } \{3\} { 3} and { 2 , 3 } \{2,3\} { 2,3} are not possible, since when you remove 3 3 3 , you must also remove 1 1 1.

题目翻译

来自谷歌生草机
题目叙述
马克邀请了一些朋友参加舞会。 其中一些朋友又邀请了新的朋友,这些被邀请的朋友又可能继续邀请其它新朋友。在这样的邀请后,现在舞会总共可能有 N N N 个人,从 1 1 1 N N N 编号。
马克觉得人数太多了,可能会拒绝一些被邀请的人。当然,一旦某个人被拒绝参加,则他邀请的朋友自然也不会参加了,同样的,被拒绝的人邀请的朋友们继续邀请的人也不会参加了。当然马克也有可能不拒绝任何人。
现在马克想知道共有多少种不同的拒绝方案。
输入格式
第一行是N,表示舞会共有 N N N 个人参加( N < = 6 N<=6 N<=6 ),其中马克的编号为 N N N .
第二行开始表示邀请的情况,其中第i行有一个数字 j j j ,表示j号朋友邀请了 i − 1 i-1 i1 号朋友
数据保证所有人都被马克直接或间接地邀请,每个人可能邀请多个人,但是每个人只会被 1 1 1 个人邀请。
输出格式
输出可能的方案数。

题目解析

step 1

先看一眼 n ≤ 6 n\le 6 n6 ,显然,一个 dfs ⁡ \operatorname{dfs} dfs 就可以过了,复杂度 Θ ( 能过 ) \Theta\left(\text{能过}\right) Θ(能过)
这里就不展示代码了,因为有脚就行,应该不会有残疾人吧

step2

无疑 step1 ⁡ \operatorname{step1} step1 里的解法就可以过了,但是,我们精益求精,追求更快的解法。
无疑可以 Θ ( N ) \Theta\left(N\right) Θ(N) 来解决。
这题可以用DP来解决,无疑使树型DP,令 f i f_i fi 为根节点为 i i i 的子树的所有方案。
考虑 f i f_i fi 是否包含全部被拒绝的,如果考虑,在进行这个节点的父亲节点的答案计算的迭代就不能通过一个简单的式子,也就是 Θ ( N ) \Theta\left(N\right) Θ(N) 的复杂度算出了,所以我们考虑 f i f_i fi 中包含全部拒绝的方案。
所以答案为 f N − 1 f_N-1 fN1 .
给出一组数据:

6
6
5
4
5
6

在这里插入图片描述
标完 f i f_i fi 之后:
在这里插入图片描述

首先我们发现,对于每个叶子节点 i i i 都满足 f i = 2 f_i=2 fi=2 ,因为每个叶子节点只有两种可能:取或不取。
然后不难根据乘法原理得出结果。
我们令 a 1 , a 2 … a n a_1,a_2\dots a_n a1,a2an i i i 的儿子
DP式: f i = ∏ i = 1 n f a i + 1 f_i=\prod_{i=1}^{n}f_{a_i}+1 fi=i=1nfai+1
说人话: f i = f a 1 × f a 2 × ⋯ × f a n + 1 \gdef\bar#1{f_{a_{#1}}} f_i=\bar{1}\times\bar{2}\times\dots\times \bar{n}+1 fi=fa1×fa2××fan+1
最后加1是因为还要算上根节点不取的情况。
代码

#include<cstdio>
#define maxn 139
using namespace std;
typedef int Type;
inline Type read(){
    
    
	char c=getchar();
	int flag=0; Type sum=0;
	while((c<'0'||c>'9')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){
    
    
		sum=(sum<<1)+(sum<<3)+(c^48);
		c=getchar();
	}
	if(flag) return -sum;
	return sum;
}
int n,x;
int head[maxn],nex[maxn],to[maxn],k;
#define add(x,y) nex[++k]=head[x];\
head[x]=k;\
to[k]=y;
int f[maxn];
void dfs(int cur,int pre){
    
    
	int flag=0;
	int tmp=1;
    for(int i=head[cur];i;i=nex[i])
	    if(to[i]!=pre){
    
    
	        dfs(to[i],cur);
	        tmp*=f[to[i]];
	        flag=1;
		} 
    if(flag) f[cur]=tmp+1;
    else f[cur]=2;
}
int main(){
    
    
    n=read();
	for(int i=1;i<n;i++){
    
    
    	x=read();
    	add(i,x) add(x,i)
	}
	dfs(n,0);
	printf("%d",f[n]-1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jiangtaizhe/article/details/109318990
ccc