问题列表:
- 硬币问题
- 渡河问题
- 01背包问题
二、渡河问题
代码块+问题描述:
/*
描述
一群N人希望只乘一条船穿过一条河,最多只能载两个人。因此,必须安排某种穿梭装置以便来回划船,以便所有人都能穿过。
每个人都有不同的划船速度;一对夫妇的速度取决于较慢者的速度。您的工作是确定使这些人相处的时间最短的策略。
输入值
输入的第一行包含一个整数T(1 <= T <= 20),即测试用例的数量。然后是T例。每个案例的第一行包含N,第二行包含N个整数,给出每个人过河的时间。每个案例前面都有一个空白行。人数不会超过1000,而且没有人花费超过100秒的时间穿越。
输出量
对于每个测试用例,打印一行,其中包含所有N个人穿过河流所需的总秒数。
样本输入
1
2
4
1 2 5 10
样本输出
17
*/
import java.util.Arrays;
import java.util.Scanner;
public class 渡河问题P {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
int N = sc.nextInt();
int p[] = new int[N];
for(int i = 0; i < N; i++){
p[i] = sc.nextInt();
}
Arrays.sort(p);
int ans = 0;
for(int i = 0; i < T; i++){
ans += f(p, N);
}
//打印最后花费的时间
System.out.println(ans);
}
//使用贪心算法,算出最短的渡河时间
static int f(int p[], int n){
int ans = 0;
while(n > 0){
//最后一个人,用最快的那个人渡
if(n == 1){
ans += p[0];
break;
//最后两个人,用次快的那个人渡
}else if(n == 2){
ans += p[1];
break;
//最后三个人,用最快的那三个人来渡
}else if(n == 3){
ans += p[0]+p[1]+p[2];
break;
//如果还有大于3的人数没有完成渡河,那么判断两种情况
}else{
//情况一:用速度最快的那个人带全部人
int s1 = p[0]+p[n-1] + p[0]+p[n-2];
//情况二:把最快的两个人先渡河,然后放回较慢的那个人来载后面的人渡河
int s2 = p[0]+p[1] + p[1]+p[n-1];
//使用ans存储每次所花费的最短渡河时间
ans += Math.min(s1, s2);
//循环一次,渡河一回,人数减二
n-=2;
}
}
return ans;
}
}
三、背包问题
代码块1(递归求解):
/*
问题描述:
有n个重量分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,
求所有挑选方案中价值总和的最大值。
1 <= n <= 100, 1 <= W <= 10000;
输入:
n = 4
(w, v) = {(2,3), (1,2), (3,4), (2,2)}
W = 5
输出:
7(选择第0、1、3号物品)
因为对每个物品只有选和不选两种情况,所以这个问题称为01背包
*/
public class 背包问题01递归 {
static int w[] = {2, 1, 3, 2};//重量表
static int v[] = {3, 2, 4, 2};//价值表
static int n = 4;//物品数量
static int W = 5;//背包的承重极限
public static void main(String[] args) {
int ww = W;//拷贝一份背包的承重极限
int ans = dfs(0, ww);
System.out.println(ans);
}
static int dfs(int i, int ww){
if(i>=n || ww<=0)return 0;
int v2 = dfs(i+1, ww);
if(ww >= w[i]){
int v1 = v[i] + dfs(i+1,ww-w[i]);
return Math.max(v1, v2);
}else{
return v2;
}
}
}
代码块2(动归求解):
//计算之前先查询,计算之后做记录
//重叠子问题不重复求解
/*
问题描述:
有n个重量分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,
求所有挑选方案中价值总和的最大值。
1 <= n <= 100, 1 <= W <= 10000;
输入:
n = 4
(w, v) = {(2,3), (1,2), (3,4), (2,2)}
W = 5
输出:
7(选择第0、1、3号物品)
因为对每个物品只有选和不选两种情况,所以这个问题称为01背包
*/
import java.util.Arrays;
public class 背包问题01动归 {
static int w[] = {2, 1, 3, 2};//重量表
static int v[] = {3, 2, 4, 2};//价值表
static int n = 4;//物品数量
static int W = 5;//背包的承重极限
public static void main(String[] args) {
int ww = W;
//横坐标n:物品总数;纵坐标W+1:背包的承重极限
res = new int[n][W+1];
//将二维数组res中的数据全部初始化为-1
for(int i = 0; i < n; i++){
Arrays.fill(res[i],-1);
}
int ans = dfs(0, ww);
System.out.println(ans);
}
static int[][]res;
static int dfs(int i, int ww){
if(i>=n || ww<=0)return 0;
//1.计算之前做查询
if(res[i][ww] >= 0){
return res[i][W];
}
int v2 = dfs(i+1, ww);
int ans;
if(ww >= w[i]){
int v1 = v[i] + dfs(i+1,ww-w[i]);
ans = Math.max(v1, v2);
}else{
ans = v2;
}
//2.计算之后做记录
res[i][ww] = ans;
return ans;
}
}