提交 8bb7b9a5 编写于 作者: qq_36480062's avatar qq_36480062

c

上级 8544e346
package RMQ;
public class ST表最优写法 {
public static void main(String[] args) {
n = 7;
init();
for (int i = 1; i <= 7; i++) {
System.out.println(query(1, i));
}
}
static int n, m;
static int[] log;
static int[][] st;
static int[] arr = {22, 23, 8, 67, 7, 7, 2};
static void init() {
log = new int[n + 2];
log[1] = 0;
for (int i = 2; i <= n + 1; i++) {
log[i] = log[i / 2] + 1;
}
st = new int[n + 2][log[n] + 1];
for (int i = 1; i <= n; i++) {
st[i][0] = arr[i - 1];
}
for (int j = 1; 1 << j <= n; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
st[i][j] = Math.min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
}
}
}
static int query(int l, int r) {
int k = log[r - l + 1];
return Math.min(st[l][k], st[r - (1 << k) + 1][k]);
}
}
......@@ -14,7 +14,7 @@ package 线性dp.背包模型;
* ...
* 求取左边的和,加上右边的和
* 左边的方案选择:1~i-1中选择,不包含i的话体积应该是j-k*i
* 则是:f[i-1,j-v[i]*k ]
* 则是:f[i-1,j-v[i]*k]
* 最终:f[i,j]=f[i-1,j]+f[i-1,j-v[i]*1]+f[i-1,j-v[i]*2]+...+f[i-1,j-v[i]*k]
* 易得f[i,j-v]= f[i-1,j-v[i]*1]+f[i-1,j-v[i]*2]+...+f[i-1,j-v[i]*k]
* 可以对应:
......
......@@ -7,12 +7,13 @@ import java.util.Scanner;
* 求最大价值
* 转换成01背包问题,
* 状态定义为f[i,j]:前i组物品可选,体积不超过j的所有选法最大值
* 状态划分:选第i组物品的第1个,选第i组物品的第2个,选第i组物品的第s[i]个,,不选第i组物品
* 状态划分:选第i组物品的第1个,选第i组物品的第2个,选第i组物品的第s[i]个,不选第i组物品
* 状态计算:显然不选第i组物品就是f[i-1,j]
* |________|+w[i][1]
* |________|+w[i][2]
* ....
* |________|+w[i][k]
* k代表地i组一共有多少物品
* 前面的最大值如何计算
* 前面的可以取的范围i-1组的物品,要选第i组的第k个物品,就要腾出来这么多
* 那么结合状态定义,最大价值就是:f[i-1,j-v[i][k]]+w[i][k]
......
package 线性dp.背包模型;
import java.util.Scanner;
/**
* 01背包问题
* 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。
* 更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。
* 今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。
* 于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。
* 他还从因特网上查到了每件物品的价格(都是整数元)。
* 他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
* 设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk
* ,则所求的总和为:
* v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk]
* 请你帮助金明设计一个满足要求的购物单。
* 输入格式
* 输入文件的第1行,为两个正整数N和m,用一个空格隔开。(其中N表示总钱数,m为希望购买物品的个数)
* 从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v和p。(其中v表示该物品的价格,p表示该物品的重要度)
* 输出格式
* 输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(数据保证结果不超过100000000)。
* 数据范围
* 1≤N<30000
* 1≤m<25,
* 0≤v≤10000,
* 1≤p≤5
* 输入样例:
* 1000 5
* 800 2
* 400 5
* 300 5
* 400 3
* 200 2
* 输出样例:
* 3900
*/
public class 开心的今明 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
n = sc.nextInt();
int e, t;
for (int i = 1; i <= n; i++) {
e = sc.nextInt();
t = sc.nextInt();
t *= e;
w[i] = t;
v[i] = e;
}
for (int i = 1; i <= n; i++) {
for (int j = m; j >= v[i]; j--) {
f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
}
}
System.out.println(f[m]);
}
static int[] f = new int[30010];
static int[] w = new int[30], v = new int[30];
static int n, m;
}
package 线性dp.背包模型;
import java.util.Scanner;
/**
* 总公司拥有M台 相同 的高效设备,准备分给下属的N个分公司。
* 各分公司若获得这些设备,可以为国家提供一定的盈利。盈利与分配的设备数量有关。
* 问:如何分配这M台设备才能使国家得到的盈利最大?
* 求出最大盈利值。
* 分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。
* 输入格式
* 第一行有两个数,第一个数是分公司数N,第二个数是设备台数M;
* 接下来是一个N*M的矩阵,矩阵中的第 i 行第 j 列的整数表示第 i 个公司分配 j 台机器时的盈利。
* 输出格式
* 第一行输出最大盈利值;
* 接下N行,每行有2个数,即分公司编号和该分公司获得设备台数。
* 答案不唯一,输入任意合法方案即可。
* 数据范围
* 1≤N≤10,
* 1≤M≤15
* 输入样例:
* 3 3
* 30 40 50
* 20 30 50
* 20 25 30
* 输出样例:
* 70
* 1 1
* 2 1
* 3 1
* 分析:
* 本题相当于AcWing 9 分组背包问题问题。每组物品要么一个不选,
* 要么同一组最多选择其中的一个,本题每个公司可获得的设备数量也是只能选择一个,
* 故状态表示f[i][j]表示在前i家公司中选择分配不超过j台设备的最大盈利。
* 状态转移方程为f[i][j] = max(f[i-1][j-k]+w[i][k]),其中j >= k。
* 另外题目要求输出任意一组合法方案,所以用个数组存储方案即可,具体第i组物品选与不选,
* 如果选,选几个,只需要找出其中的一个k,使得f[i][j] == f[i-1][j-k]+w[i][k]即可使得第i个物品选k个是合法的方案。
*/
public class 机器分配 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
w[i][j] = sc.nextInt();
}
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];//一个都不选
for (int k = 1; k <= j; k++) {
//最多选k个,把k个物品
f[i][j] = Math.max(f[i][j], f[i - 1][j - k] + w[i][k]);
}
}
}
System.out.println(f[n][m]);
int j = m;
for (int i = n; i != 0; i--) {//倒序往前找决策
for (int k = 0; k <= j; k++) {
if (f[i][j] == f[i - 1][j - k] + w[i][k]) {
way[i] = k;
j -= k;
break;
}
}
}
for (int i = 1; i <= n; i++) {
System.out.println(i + " " + way[i]);
}
}
static int[] way = new int[20];
static int[][] f = new int[20][20];
static int n, m;
static int[][] w = new int[20][20];
}
......@@ -12,16 +12,49 @@ import java.util.Scanner;
* 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,
* 且价值总和最大。
* 输出最大价值。
* 状态定义:f[i,j]:只从前i种物品选,且总体积不超过j的选法
* 属性max:最大价值
* 状态计算:
* 01背包:f[i,j]=max( f[i-1,j] ,f[i-1][j-v[i]]+w[i])
* 完全背包:f[i,j]=max(f[i-1,j] ,f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*k+w[i]*k)
* 易得f[i,j-v]= max(f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*k+w[i]*k)
* 可以对应:
* 当然可以替换f[i,j]=max( f[i-1,j],f[i,j-v] )
* 多重背包:f[i,j]=max(f[i-1,j] ,f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*s[i]+w[i]*s[i])
*/
public class 混合背包 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
V = sc.nextInt();
for (int i = 0; i < N; i++) {
for (int i = 1; i <= N; i++) {
v[i] = sc.nextInt();
w[i] = sc.nextInt();
t[i] = sc.nextInt();
}
for (int i = 1; i <= N; i++) {
if (t[i] == 0) {
for (int j = v[i]; j <= V; j++) {
f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
}
} else {
if (t[i] == -1) t[i] = 1;
for (int k = 1; k <= t[i]; k *= 2) {
for (int j = V; j >= k * v[i]; j--) {
f[j] = Math.max(f[j], f[j - k * v[i]] + w[i] * k);
}
t[i] -= k;
}
if (t[i] > 0) {
for (int j = V; j >= t[i] * v[i]; j--) {
f[j] = Math.max(f[j], f[j - t[i] * v[i]] + w[i] * t[i]);
}
}
}
}
System.out.println(f[V]);
}
static int[] v = new int[1010], w = new int[1010], t = new int[1010], f = new int[1010];
static int N, V;
}
......@@ -2,6 +2,42 @@ package 线性dp.背包模型;
import java.util.Scanner;
/**
* 有 N 件物品和一个容量是 V
* 的背包。每件物品只能使用一次。
* 第 i件物品的体积是 vi,价值是 wi
* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
* 输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 1…N
* 输入格式
* 第一行两个整数,N,V
* ,用空格隔开,分别表示物品数量和背包容积。
* 接下来有 N
* 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i
* 件物品的体积和价值。
* 输出格式
* 输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
* 物品编号范围是 1…N
* 数据范围
* 0<N,V≤1000
* 0<vi,wi≤1000
* 输入样例
* 4 5
* 1 2
* 2 4
* 3 4
* 4 6
* 输出样例:
* 1 4
* 对应图论最短路问题
* f[n-1,m]->f[n,m]边权重为0
* f[n-1,m-v[i]]+w[i]->f[n,m] 边权重为w[i]
* 要求字典序最小:
* 可能最大价值有多种方案
* 对于一个物品:有三种情况,必选,可选,不能选
* 如果物品可选那就一定选则是字典序最小方案
* 因为是1..n顺序判断的最大价值
* 要倒序从下面到上面做dp
*/
public class 背包问题求具体方案 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
......
package 线性dp.背包模型;
import java.util.Scanner;
/**
* 给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。
* 输入格式
* 第一行,包含两个整数n和m。
* 接下来n行,每行包含一个整数,表示一种货币的面值。
* 输出格式
* 共一行,包含一个整数,表示方案数。
* 数据范围
* n≤15,m≤3000
* 输入样例:
* <p>
* 3 10
* 1
* 2
* 5
* 输出样例:
* 10
* 分析:
* 本题与上一题买书问题基本一模一样,只是方案数可能很大,需要用long long来存储。
* 状态表示:f[i][j]表示用前i种面值的货币组成面值为j的方案数,
* 状态转移方程为f[i][j] = f[i-1][j] + f[i][j-v],边界状态为f[0][0] = 1。
* 完全背包问题
*/
public class 货币系统 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
v[i] = sc.nextInt();
}
f[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = v[i]; j <= m; j++) {
f[j] += f[j - v[i]];
}
}
System.out.println(f[m]);
}
static int[] v = new int[20];
static long[] f = new long[3010];
static int n, m;
}
package 线性dp.背包模型;
import java.util.ArrayList;
import java.util.Scanner;
/**
* 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。
* 更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。
* 今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
* 如果要买归类为附件的物品,必须先买该附件所属的主件。
* 每个主件可以有0个、1个或2个附件。
* 附件不再有从属于自己的附件。
* 金明想买的东西很多,肯定会超过妈妈限定的N元。
* 于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。
* 他还从因特网上查到了每件物品的价格(都是10元的整数倍)。
* 他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
* 设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk,则所求的总和为:
* v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk](其中*为乘号)
* 请你帮助金明设计一个满足要求的购物单。
* 输入格式
* 输入文件的第1行,为两个正整数,用一个空格隔开:N m,其中N表示总钱数,m为希望购买物品的个数。
* 从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数v p q,其中v表示该物品的价格,p表示该物品的重要度(1~5),q表示该物品是主件还是附件。
* 如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号。
* 输出格式
* 输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。
* 数据范围
* N<32000,m<60,v<10000
* 输入样例:
* 1000 5
* 800 2 0
* 400 5 1
* 300 5 1
* 400 3 0
* 500 2 0
* 输出样例:
* 2200
* 分析:
* 本题考察AcWing 9 分组背包问题的应用,分组背包问题是每组物品最多只能选一个,
* 而本题是每组物品可以选任意个,并且组内物品的体积,价值都不同。
* 简单描述下题意,要买不超过N元钱的物品,物品分主件和附件,每个主件可能有多个附件,
* 要想买附件必须先买其附属的主件,要找出花钱不超过N元买的物品的最大价值,
* 一件物品的价值等于该物品的价格与重要度的乘积。首先考虑属性的存储,
* 主件附件都要考虑物品的价格及价值(价格*重要度),所以可以用个pair存储。
* 在进行状态转移时,遍历一个主件时考虑买几个附件,设一共有x个附件,
* 则买附件的情况一共有2^x种,可以用状态压缩表示对这x种附件的购买方式,比如有2个附件,
* 10表示只买第二个附件。其它过程与分组背包完全一致,只需要注意价格和价值的累加即可。
* 分组背包:把每一个主件与附件的组合看成一个组
* 状态定义:f[i,j]代表前i种主件可选价值不超过j的所有方案
*/
public class 金明的预算方案 {
static class node {
int v, m;
public node(int v, int m) {
this.v = v;
this.m = m;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
m = sc.nextInt();
n = sc.nextInt();
int v, p, q;
for (int i = 1; i <= n; i++) {
v = sc.nextInt();
p = sc.nextInt();
q = sc.nextInt();
p *= v;
if (q != 0) {
fu[q].add(new node(v, p));
} else {
zhu[i] = new node(v, p);
}
}
int t, e;
for (int i = 1; i <= n; i++) {
if (zhu[i] != null) {//是主件
for (int j = m; j >= 0; j--) {
for (int k = 0; k < 1 << fu[i].size(); k++) {//有哪些附件,二进制枚举所有选和不选的情况
t = zhu[i].v;
e = zhu[i].m;
for (int u = 0; u < fu[i].size(); u++) {
if ((k >> u & 1) == 1) {
t += fu[i].get(u).v;
e += fu[i].get(u).m;
}
}
if (j >= t) f[j] = Math.max(f[j], f[j - t] + e);
}
}
}
}
System.out.println(f[m]);
}
static int[] f = new int[32009];
static node[] zhu = new node[70];
static ArrayList<node>[] fu = new ArrayList[70];
static {
for (int i = 0; i < fu.length; i++) {
fu[i] = new ArrayList<node>();
}
}
static int n, m;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册