题目二
题目描述
/*
问题描述:
有一棵n个节点的树,有一条边被选定。 小美想知道对于所有经过这条选定边的所有树上简单路径,最长的那条有多长
一条简单的路径的长度指这条简单路径上的边的个数
输入描述:
第一行一个整数n,表示树的结点个数
第二行n-1 个整数,第i整数 pi: 表示节点i-1 和 pi 之间有一条边相连。
第三行两个整数 x,y,表示这条选定的边。保证这条边一定是树上的一条边。
对于全部数据,2<10e5, 1<=x,y<=n 。x !=y。保证输入数据正确描述一棵树,开且
(x y)是树上的一条边
输出描述:
输出一行,一个整数,表示所有经过选定边的树上简单路径中,最长的那条的长度
*/
思路
重点在于理解题意!!!
树回溯问题,分别求出两个端点除彼此端点(不走彼此端点)的最长路径,两端路径数目相加再加上由这两个端点组成的这一条路径,即为答案。
但是通过率为91%,没有全部通过
代码
import java.util.ArrayList;
import java.util.Scanner;
//通过率91%
public class Main {
static int n, x, y; // n 表示节点数,x 和 y 表示所选边的两个端点
static ArrayList<Integer>[] edges; // 定义邻接表存储图
static boolean[] visited; // 标记当前节点是否已访问过
static int pathMax; // 存储被删去的边左右两部分的最大深度
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
edges = new ArrayList[n + 1];
visited = new boolean[n + 1];
//建立邻接表
for (int i = 1; i <= n; i++) {
edges[i] = new ArrayList<>();
}
for (int i = 1; i < n; i++) {
int u = sc.nextInt();
int v = i + 1;
edges[u].add(v);
edges[v].add(u);
}
//确定边
x = sc.nextInt();
y = sc.nextInt();
sc.close();
int res = 0;
visited[y] = true;//确保不走y这个端点
dfs(x,0);
visited[y] = false;
res +=pathMax;
pathMax = 0;
visited[x] = true;//确保不走x这个端点
dfs(y,0);
visited[x] = false;
res += pathMax;
System.out.println(res+1);//最后加上本身x,y这一条路径 res+1
}
/**
* 深度优先遍历以u节点为起点的路径
* @param u
* @param depth
*/
private static void dfs(int u,int depth) {
visited[u] = true;
pathMax = Math.max(pathMax,depth);
for (int v : edges[u]) {
if (!visited[v]) {
dfs(v,depth + 1);
}
}
}
}
题目三
题目描述
/*
小美不干外卖配送了,转行开了一家水果店。
一天她接到了一个大单,客户订购了 n 个水果,并且要求打包成多个果篮,一个果篮最多装 m 个水果。
为了包装方便,水果按从 1 到 n 编号,同一个果篮里装的水果编号必须是连续的。果篮的成本与容积成线性关系。为了估计容积,小美简单地用样本中点估计了一下。具体来说,假设一个果篮中装的最大的水果体积是 u,最小的是 v,那么这个果篮的成本就是 k × floor((u+v)/2) + s,其中 k 是果篮中装入水果的个数,s 是一个常数,floor(x) 是下取整函数,比如 floor(3.8)=3, floor(2)=2。
客户并没有规定果篮的数量,但是希望果篮的成本越小越好,毕竟买水果就很贵了。请求出小美打包这 n 个水果所用的最小花费。
输入描述
第一行三个正整数 n, m, s。意义如题面所示。
第二行 n 个正整数 a1, a2, ..., an,表示每个水果的体积。
对于全部数据,1 ≤ n ≤ 1e4, 1 ≤ m ≤ 1e3, m ≤ n, 1 ≤ ai, s ≤ 1e4。
输出描述
输出一个整数,表示打包这 n 个水果果篮的最小成本。
样例输入
6 4 3
1 4 5 1 4 1
样例输出
21
*/
思路
思路
1. 递归 深度遍历
时间复杂度会很高,估计不能全通过!!!
每个篮子存放的数目为1,2,... , m 。共m种可能;每一种情况下依次再递归剩下的水果;最后取最小的结果。
2.动态规划
也可用动态规划,没搞出来,后边更新
代码
import java.util.Scanner;
public class Main {
//水果打包
static int res = Integer.MAX_VALUE;
static int m;
static int s;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
m = scanner.nextInt();
s = scanner.nextInt();
int[] fruits = new int[n];
for (int i = 0; i < n; i++) {
fruits[i] = scanner.nextInt();
}
dfs(fruits,0,0);
System.out.println(res);
}
public static void dfs(int[] fruits,int index,int preCost){
if(preCost > res) return;//剪枝操作
if(index >= fruits.length){
res = preCost;
return;
}
int tempCost = 0;
int theBig = Integer.MIN_VALUE;//保存装入的水果里最大水果的体积
int theSmall = Integer.MAX_VALUE;//保存装入的水果里最小水果的体积
int count = 0;//装入水果的个数
for (int i = index; i < Math.min(index + m,fruits.length); i++) {
theBig = Math.max(theBig,fruits[i]);
theSmall = Math.min(theSmall,fruits[i]);
count++;
tempCost = count * ((theBig + theSmall)/2) + s;
dfs(fruits,i+1,preCost + tempCost);
}
}
}