回溯法之生命之树

回溯法Q2——生命之树

生命之树这道题是参考了南墙的代码的
我之前做这种图的都是将顶点邻接关系存储在邻接矩阵中的,
之前在蓝桥杯大臣的旅费这道题中有用过自定义图结构,这道题也类似。我对dfs并不陌生不过,倒是没有想到用回溯来统计每个结点的最大和谐值,通常是回溯后取消标记。

/*
生命之树
在X森林里,上帝创建了生命之树。
他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,
代表这个点的和谐值。上帝要在这棵树内选出一个非空节点集S,
使得对于S中的任意两个点a,b,都存在一个点列 {a, v1, v2, ..., vk, b} 
使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。
在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。
这个最大的和就是上帝给生命之树的评分。
经过atm的努力,他已经知道了上帝给每棵树上每个节点上的整数。
但是由于 atm 不擅长计算,他不知道怎样有效的求评分。
他需要你为他写一个程序来计算一棵树的分数。

「输入格式」
第一行一个整数 n 表示这棵树有 n 个节点。
第二行 n 个整数,依次表示每个节点的评分。
接下来 n-1 行,每行 2 个整数 u, v,表示存在一条 u 到 v 的边。
由于这是一棵树,所以是不存在环的。

「输出格式」
输出一行一个数,表示上帝给这棵树的分数。

「样例输入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5

「样例输出」
8

「数据范围」
对于 30% 的数据,n <= 10
对于 100% 的数据,0 < n <= 10^5, 每个节点的评分的绝对值不超过 10^6 。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 3000ms
 */
package 第六届;

import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class 生命树_网友版 {
	static int[] nodeValue;//存放各个点的和谐值
	static List<Integer>[] point;//存放各个点的包含的邻接边
	static int[] value;//存放以某个点为根节点情况下的最大和谐值和
	static int ans=0;//记录最大结果
	static void dfs(int son,int father) {
		value[son]=nodeValue[son];//以son为根节点,一开始时其最大和谐值为它本身
		for(int i=0;i<point[son].size();i++) {//枚举与son相连的结点
			int next=point[son].get(i);
			//当枚举的下一个结点是son先前经过的点father 跳过 防止绕圈
			if(next==father)continue;//如果都continue掉说明这个点是叶子结点
			dfs(next,son);
			//回溯(子节点平行状态都走完没得走了或者说状态没得转移了才会回溯)得到父节点与子节点和
			if(value[next]>0)//子节点的和谐值
				value[son]+=value[next];
			ans=Math.max(ans, value[son]);
		}
		
	}
	public static void main(String[] args) {
		Scanner reader=new Scanner(System.in);
		int n=reader.nextInt();
		nodeValue=new int [n+1];
		value=new int[n+1];
		point=new LinkedList[n+1];
		for(int i=1;i<=n;i++) {
			nodeValue[i]=reader.nextInt();
			point[i]=new LinkedList();
		}
		for(int i=1;i<n;i++) {
			int x=reader.nextInt();
			int y=reader.nextInt();
			point[x].add(y);
			point[y].add(x);
		}
		dfs(1,-1);//从0号结点开始搜索 假设它的父节点为-1可以为其他的无关量
		System.err.println(ans);
	}

}

**然后又想起了之前蓝桥杯真题上的抽签这道题。也是用的回溯法标记选的哪个国家的人。这里一并总结了。**

回溯法Q3——抽签

 /*题目描述
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。

C国最多可以派出2人。

D国最多可以派出1人。

E国最多可以派出1人。

F国最多可以派出3人。
那么最终派往W星的观察团会有多少种国别的不同组合呢?

下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF
....

(以下省略,总共101行)

*/
package 排列组合类;

public class 抽签 {
	//数组a[]表示每个国家可以派出的最多名额 0-a[k]
	static int a[]={4,2,2,1,1,3};
	static int ans;
	static void dfs(int index,int cnt,String s) {
		//当前选a[index]类 还有cnt个名额 当前已经选的人有s
		System.out.println(index+" "+cnt+" "+s);
		
		if(cnt<0) {return;}
		
		if(index==6) {
			if(cnt==0) {
				ans++;
				System.out.println(s);
			}
			return;
		}
		//{4,2,2,1,1,3}
		//{AAAA,BB,CC,D,E,FFF}
		String s2=s;
		for(int i=0;i<=a[index];i++) {
			dfs(index+1,cnt-i,s2);
			s2=s2+(char)('A'+index);
		}
		
	}

	public static void main(String[] args) {
		dfs(0,5,"");
		System.out.println(ans);

	}

}
发布了21 篇原创文章 · 获赞 0 · 访问量 473

猜你喜欢

转载自blog.csdn.net/weixin_44855907/article/details/104756476