算法训练 || G将军(递归回溯)

G 将军有一支训练有素的军队,这个军队除开 G 将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是 G 将军)。现在 G 将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,为了增加队员的独立性,要求如果一名士兵在队中,他的直接上级不能在队中。
请问,G 将军有多少种派出队的方法。注意,G 将军也可以作为一个士兵进入队。
输入格式
输入的第一行包含一个整数 n,表示包括 G 将军在内的军队的人数。军队的士兵从 1 至 n 编号,G 将军编号为 1。
接下来 n-1 个数,分别表示编号为 2, 3, …, n 的士兵的直接上级编号,编号 i 的士兵的直接上级的编号小于 i。
输出格式
输出一个整数,表示派出队的方案数。由于数目可能很大,你只需要输出这个数除 10007 的余数即可。
样例输入 1
3
1 1
样例输出 1
4
样例说明
这四种方式分别是:
1.选 1;
2.选 2;
3.选 3;
4.选 2, 3。
样例输入 2
7
1 1 2 2 3 3
样例输出 2
40

public class G将军 {
	static int count=0,n=0;
	static ArrayList<Integer> s=new ArrayList<>();
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n=in.nextInt();
		int arr[]=new int[n];
		//题目说编号 i 的士兵的直接上级的编号小于 i,所以编号为0的士兵就是G将军,而其他士兵从i=1开始数(共n-1个 )
		for(int i=1;i<n;i++){
			arr[i]=in.nextInt();//第i个士兵的上级是arr[i]
		}	
		dfs(arr,0);
		System.out.println(count-1);//-1是减去"全部人都不去的情况"
		
	}

	public static void dfs(int arr[],int num) {
		if(n==num) {
			count++;
			return ;
		}
		else {
			//编号为num的士兵有上级在队伍里
			if(s.contains(arr[num])) {//如果 s 里面已经包含了 num 的领导,num 就不能去了,继续往下遍历  
				dfs(arr,num+1);
			}
			else {
				// 如果不包含 num 的领导,num 可以选择去也可以选择不去  
				//可以理解为一颗树,num位置的士兵去或不去都要对相应的树的分支进行处理,也可以理解为数学上的分类相加,所以这里写两次dfs(arr,num+1);
				dfs(arr,num+1);//不去,直接递归进入下一个编号处理
				
				s.add(num+1);//去,添加进去(添加的是士兵的编号,即num+1,因为士兵的编号是从1开始的)
				dfs(arr,num+1);//继续往后走
				
				//回溯,前面进去一个,这里出去一个,可以避免回溯过程有"脏数据"影响 
				s.remove(s.size()-1);
			}
		}
	}

}
发布了5 篇原创文章 · 获赞 8 · 访问量 482

猜你喜欢

转载自blog.csdn.net/Awwwze/article/details/104314567