一、字符串变形
输入两个字符串a和b,a的长度小于b的长度。现在可以在a中的每个位置插入任意字符,使得最终a的长度等于b的长度,问最后a和b中对应位置字符不同的位置的个数。
这个问题可以看做是:带约束的最长公共子序列
考虑形如abcx 和ayybc的两个字符串,第一个字符串不能添加太多字符,否则会导致它的长度太长。当a[i]=b[j]时,i必须不能大于j,否则a[i]是不可能等于j的。
这道题测试样例过于简单,以至于很多错误解法也能全部通过。
import java.util.Scanner;
public class Main {
Main() {
Scanner cin = new Scanner(System.in);
char[] a = cin.next().trim().toCharArray(), b = cin.next().trim().toCharArray();
int[][] m = new int[a.length][b.length];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (i > 0) m[i][j] = Math.max(m[i - 1][j], m[i][j]);
if (j > 0) m[i][j] = Math.max(m[i][j - 1], m[i][j]);
if (a[i] == b[j] && a.length - i <= b.length - j && i <= j) {
int last = 0;
if (i > 0 && j > 0) last = m[i - 1][j - 1];
m[i][j] = Math.max(m[i][j], last + 1);
}
}
}
int common = m[a.length - 1][b.length - 1];
int add = b.length - a.length;
// System.out.println(common);
int ans = b.length - common - add;
System.out.println(ans);
}
public static void main(String[] args) {
new Main();
}
}
二、概率+动态规划
N个人,M个礼品,每个礼品的个数为C[i],第i个人选择第j个礼品的概率为p[i][j],当发放礼品时,N个人一次性确定好自己要什么礼品,然后按照顺序一次发放,若某种类型的礼品没了,就不给要这个礼品的人发了。因为礼品个数有限,问期望有多少人能够拿到礼品。
关键在于明白问题转化:期望拿到礼品的人数=每种礼品期望发给的任务。因为人和礼品之间时一一对应的。
定义数组f[M][N],f[i][j]表示第i种礼品被要求次数为j的概率,N从0~N递增推导就可以得到最终矩阵,这个过程相当于滚动数组形式的动态规划。
import java.util.Scanner;
public class Main {
int N, M;
int[] c;
double p[][];
double left[][];
Main() {
Scanner cin = new Scanner(System.in);
N = cin.nextInt();
M = cin.nextInt();
c = new int[M];
p = new double[N][M];
for (int i = 0; i < M; i++) {
c[i] = cin.nextInt();
if (c[i] > N) c[i] = N;
}
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) p[i][j] = cin.nextDouble();
left = new double[M][N + 1];
for (int i = 0; i < left.length; i++) left[i][0] = 1;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
for (int k = N; k >= 0; k--) {
left[j][k] = left[j][k] * (1 - p[i][j]);
if (k > 0) {
left[j][k] += left[j][k - 1] * p[i][j];
}
}
}
}
double s = 0;
for (int i = 0; i < M; i++) {
for (int j = 0; j <= N; j++) {
s += left[i][j] * Math.min(c[i], j);
}
}
System.out.printf("%.1f", s);
}
public static void main(String[] args) {
new Main();
}
}
三、数组排序:贪心
一个无序数组,每次只能执行一种操作:把任意一个元素移动到末尾。问最少经过多少次操作能够使得数组变得有序。
对于元素x,只要它后面有比它小的元素,它就必然要被挪到最后去。而对于需要挪到最后去的一批元素,必然是优先移动比较小的那些元素,这样才能保证它们尽量靠前。
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.stream.Collectors;
public class Main {
Main() {
Scanner cin = new Scanner(System.in);
int N = cin.nextInt();
int[] a = new int[N];
for (int i = 0; i < N; i++) a[i] = cin.nextInt();
int s = 0;
while (true) {
LinkedList<Integer> left = new LinkedList<>();
LinkedList<Integer> right = new LinkedList<>();
int mi = Integer.MAX_VALUE;
for (int i = a.length - 1; i >= 0; i--) {
if (mi < a[i]) {
right.add(a[i]);
} else {
left.add(a[i]);
}
mi = Math.min(mi, a[i]);
}
right.sort(Comparator.comparing(x -> x));
s += right.size();
if (right.size() == 0) break;
int ai = 0;
for (int i : left) a[N - 1 - right.size() - (ai++)] = i;
for (int i : right) a[ai++] = i;
}
System.out.println(s);
}
public static void main(String[] args) {
new Main();
}
}
原文地址:https://www.cnblogs.com/weiyinfu/p/9508954.html
时间: 2024-11-07 18:44:31