kuangbin带你飞:起飞~
原题链接:Max Sum Plus Plus 原题链接:Ignatius and the Princess IV 原题链接:Monkey and Banana 原题链接:Super Jumping! Jumping! Jumping! 原题链接:Piggy-Bank 原题链接:免费馅饼 原题链接:Tickets 原题链接:最少拦截系统 原题链接:FatMouse’s Speed 未完待续……
思路:题意为找出n个数中m个不相交子段的最大和
1.定义状态dp[i][j],意为前 j 个数中选出的 i 组数的最大和,若简单DP状态转移为
dp[i][j]=MAX{ dp[i][j-1],dp[i-1][k] }+num[j] (i-1
dp当前状态 [j]=MAX{ dp当前状态 [j-1],dp上一状态 [k] }+num[j] (i-1
4.最终的状态转移方程就变为:
dp[j]=MAX{ dp[j-1],lastMax[j-1] }+num[j] (i-1import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int mLen = (int) 1e6 + 10;
static int[] num = new int[mLen];
static int[] dp = new int[mLen];
static int[] lastMax = new int[mLen];
static int inf = 1 << 30;
static int n, m;
public static void main(String[] args) {
//1e6的数据,使用输入输出挂
InputReader in = new InputReader();
PrintWriter out = new PrintWriter(System.out);
while (in.hasNext()) {
n = in.nextInt();
m = in.nextInt();
for (int i = 1; i <= m; i++) {
num[i] = in.nextInt();
}
//状态初始化
Arrays.fill(dp, 0);
Arrays.fill(lastMax, 0);
int Max = -inf;
for (int i = 1; i <= n; i++) {
Max = -inf;
for (int j = i; j <= m; j++) {
dp[j] = Math.max(dp[j - 1], lastMax[j - 1]) + num[j];
lastMax[j - 1] = Max;
Max = Math.max(Max, dp[j]);
}
}
//利用缓存加速,比syso快的多
out.println(Max);
}
//用了out记得要关闭
out.close();
}
}
class InputReader {
BufferedReader bf;
StringTokenizer st;
InputReader() {
bf = new BufferedReader(new InputStreamReader(System.in));
}
boolean hasNext() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(bf.readLine());
} catch (Exception e) {
return false;
}
}
return true;
}
String next() {
if (hasNext()) {
return st.nextToken();
}
return null;
}
int nextInt() {
return Integer.parseInt(next());
}
}
2. Ignatius and the Princess IV
思路:不知道哪里用到DP了。。。数据很水,直接快排输出num[n+1/2]都可以AC,复杂度O(nlogn)。为了达到练习目的,此处采用Boyer-Moore 投票算法,复杂度O(n)。import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
int[] num = new int[n];
for (int i = 0; i < n; i++) {
num[i] = sc.nextInt();
}
int ans = 0, element = 0;
for (int i = 0; i < n; i++) {
if (ans == 0) {
element = num[i];
}
if (num[i] == element) {
ans += 1;
} else {
ans -= 1;
}
}
System.out.println(element);
}
}
}
3. Monkey and Banana
思路:把砖块先按长度排序,问题就转化为了求上升子序列的最大和。宽度用于比较,高为值。注意每块砖有6种放置方法与最后的输出格式即可。import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class brick implements Comparable<brick> {
int x, y, h;
int maxH;
public brick(int x, int y, int h, int maxH) {
this.x = x;
this.y = y;
this.h = h;
this.maxH = maxH;
}
@Override
public int compareTo(brick b2) {
if (this.x == b2.x) {
if (this.y == b2.y) {
return 0;
} else {
return this.y > b2.y ? 1 : -1;
}
} else {
return this.x > b2.x ? 1 : -1;
}
}
}
public class Main {
static int count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
count++;
if (n == 0) {
return;
}
ArrayList<brick> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
int h = sc.nextInt();
list.add(new brick(x, y, h, h));
list.add(new brick(y, x, h, h));
list.add(new brick(h, x, y, y));
list.add(new brick(x, h, y, y));
list.add(new brick(y, h, x, x));
list.add(new brick(h, y, x, x));
}
Collections.sort(list);
int res = 0;
for (int i = 1; i < list.size(); i++) {
for (int j = 0; j < i; j++) {
brick bi = list.get(i), bj = list.get(j);
if (bi.x > bj.x && bi.y > bj.y) {
bi.maxH = Math.max(bi.maxH, bj.maxH + bi.h);
}
}
res = Math.max(res, list.get(i).maxH);
}
//注意格式!!!最后还有一个空格!!!我PE了三回才发现
System.out.printf("Case %d: maximum height = %d \n", count, res);
}
}
}
5. Super Jumping! Jumping! Jumping!
思路:上升子序列最大和模板import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
if (n == 0) {
return;
}
int max = 0;
int[] num = new int[n];
int[] dp = new int[n];
for (int i = 0; i < n; i++) {
num[i] = sc.nextInt();
dp[i] = num[i];
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (num[i] > num[j]) {
dp[i] = Math.max(dp[i], dp[j] + num[i]);
}
}
max = Math.max(max, dp[i]);
}
System.out.println(max);
}
}
}
6. Piggy-Bank
解题思路:需要装满的完全背包的变体,求最小价值。import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N, E, F, n,p,w;
static final int inf = 0x3f3f3f3f;
static int[] dp = new int[(int) 1e4 + 10];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
for (int i = 0; i < N; i++) {
E = sc.nextInt();
F = sc.nextInt();
n = sc.nextInt();
int temp = F - E;
Arrays.fill(dp, inf);
dp[0] = 0;
for (int j = 1; j <= n; j++) {
p=sc.nextInt();
w=sc.nextInt();
for (int k = w; k <=temp ; k++) {
dp[k]=Math.min(dp[k],dp[k-w]+p);
}
}
if (dp[temp] != inf) {
System.out.printf("The minimum amount of money in the piggy-bank is %d. \n", dp[temp]);
} else {
System.out.printf("This is impossible. \n");
}
}
}
}
7. 免费馅饼
解题思路:数塔问题,倒着DP就可以了,可以将数据想成一个倒三角,最后的出口是唯一确定的,只要递归地获取上一层左中右位置的最大值即可
递推式:dp[i][j] = max(dp[i + 1][j - 1], dp[i + 1][j], dp[i + 1][j + 1]) + pie[i][j];import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int n, t, x;
static final int maxN = (int) 1e5 + 5;
static int[][] dp = new int[maxN][15];
static int[][] pie = new int[maxN][15];
public static void main(String[] args) {
InputReader in = new InputReader();//快速读入
while (in.hasNext()) {
n = in.nextInt();
if (n == 0) {
return;
}
for (int i = 0; i < maxN; i++) {
for (int j = 0; j < 15; j++) {
dp[i][j] = 0;
pie[i][j] = 0;
}
}
int end = 0;
for (int i = 0; i < n; i++) {
x = in.nextInt() + 1;
t = in.nextInt();
pie[t][x] += 1;//方便处理0位置
end = Math.max(end, t);
}
for (int i = end; i >= 0; i--) {
for (int j = 1; j <= 11; j++) {
dp[i][j] = max(dp[i + 1][j - 1], dp[i + 1][j], dp[i + 1][j + 1]) + pie[i][j];
}
}
System.out.println(dp[0][6]);
}
}
private static int max(int a, int b, int c) {
return Math.max(a, Math.max(b, c));
}
}
class InputReader {
BufferedReader bf;
StringTokenizer st;
InputReader() {
bf = new BufferedReader(new InputStreamReader(System.in));
}
boolean hasNext() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(bf.readLine());
} catch (Exception e) {
return false;
}
}
return true;
}
String next() {
if (hasNext()) {
return st.nextToken();
}
return null;
}
int nextInt() {
return Integer.parseInt(next());
}
}
8. Tickets
解题思路:along存储每个人单独所需时间,together存储每个人和他前面一起所需时间。则到第i个人所需最少时间就是他自己买加上i-1人用的时间或者他和前一个人一起买,前i-2人用的时间。
递推式:dp[i]=MIN{dp[i-1]+along[i],dp[i-2]+together[i]}import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] alone = new int[2020];
static int[] together = new int[2020];
static int[] dp = new int[2020];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int t = 0; t < T; t++) {
int k = sc.nextInt();
for (int i = 1; i <= k; i++) {
alone[i] = sc.nextInt();
}
for (int i = 2; i <= k; i++) {
together[i] = sc.nextInt();
}
dp[1] = alone[1];
dp[2] = Math.min(alone[1] + alone[2], together[2]);
for (int i = 3; i <= k; i++) {
dp[i] = Math.min(dp[i - 1] + alone[i], dp[i - 2] + together[i]);
}
int h = dp[k] / 3600 + 8;
int m = dp[k] % 3600 / 60;
int s = dp[k] % 60;
//12点时am,pm都能过,可能是没有12点时的数据
if (h > 12) {
System.out.printf("%02d:%02d:%02d pm \n", h - 12, m, s);
} else {
System.out.printf("%02d:%02d:%02d am \n", h, m, s);
}
}
}
}
9. 最少拦截系统
解题思路:求最长上升子序列的长度,LIS模板题。注意是多组数据import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] h = new int[1010];
static int[] dp = new int[1010];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
h[i] = sc.nextInt();
dp[i] = 1;
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j =i + 1; j < n; j++) {
if (h[j] > h[i]) {
dp[j] = Math.max(dp[i] + 1, dp[j]);
}
ans = Math.max(ans, dp[i]);
}
}
System.out.println(ans);
}
}
}
10. FatMouse’s Speed
解题思路:先排序,就转化为求最长降/升序子序列,注意还要输出路径
不知道错在哪了,求指点import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
class mouse implements Comparable<mouse> {
int id, w, v;
public mouse(int id, int w, int v) {
this.id = id;
this.w = w;
this.v = v;
}
@Override
public int compareTo(mouse m2) {
if (this.w==m2.w){
return this.v>m2.v?1:-1;
}else {
return this.w<m2.w?1:-1;
}
}
}
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
ArrayList<mouse> nest=new ArrayList<>();
int[] dp=new int[1010];
Arrays.fill(dp,1);
int index=0,w=0,v=0;
while (sc.hasNextInt()){
w=sc.nextInt();
v=sc.nextInt();
nest.add(new mouse(++index,w,v));
}
Collections.sort(nest);
System.out.println(index);
int res=0;
mouse mi,mj;
for (int i = 0; i < index; i++) {
for (int j = i+1; j <index ; j++) {
mi=nest.get(i);
mj=nest.get(j);
if (mi.w>mj.w&&mi.v<mj.v){
dp[j]=Math.max(dp[j],dp[i]+1);
}
}
res=Math.max(res,dp[i]);
}
System.out.println(res);
for (int i = index-1; i >=0 ; i--) {
if (dp[i]==res){
System.out.println(nest.get(i).id);
res--;
}
}
}
}