好不容易来到新的一关,有一个长长的吊桥,吊桥的尽头是下水管道,其中随机的木板存在缺失,一旦踩到就会死亡,死亡后如果还有剩余的生命将在原地复活且不受木板缺失影响,但会消耗一次生命;如果跨过了管道,将跌入悬崖,通关失败。超级玛丽从起点S开始,可以走到下个木板(计+1),也可以跳着跨过一个块(计2)或两个木板(计3),最终必须刚好走到终点
现在给定超级玛丽当前的生命数M,吊桥的长度N,缺失的木板数K,以及随机缺失的木板编号数组L,请帮忙计算一下,超级玛丽有多少种方法可以通过此关
解答要求
时间限制:C/C++ 1000ms,其他语言: 2000ms 内存限制:C/C++ 256MB,其他语言:512MB
输入
超级玛丽当前生命数: M (1<=M<=5, 整数) 吊桥的长度: N (1 <=N<=32,整数) 缺失木板数: K (1<=N<=32,整数) 缺失木板编号数组: L (长度及编号的内容不大于N的编号数组, 1<=Li<=N
输出
输出通过此关的吊桥走法个数,如果不能通过此关,请输出0
样例1
输入:2 2 1 4 输出:4 解释: 2个生命,2个木板,缺失1个木板 第2个木板有缺失,一共有 4种走法:
样例2
输入:1 3 2 1 3 输出:1 解释: 1个生命,3个木板,缺失2个木板 第1个和第3个有缺失 只有一种走法: 2, 2,其他都不能通关:
xpublic class Bridge {
private int[] L;
private int M, N, K;
private int[][] emeo;
private Set<Integer> set;
// 记忆化搜索「回溯」
public int f1(int M, int N, int K, int[] L) {
this.M = M;
this.N = N;
this.K = K;
this.L = L;
emeo = new int[N + 2][M + 1];
set = new HashSet<>();
for (int i : L) set.add(i);
for (int i = 0; i <= N + 1; i++) Arrays.fill(emeo[i], -1);
return backtrack(0, M);
}
private int backtrack(int i, int j) {
if (i > N + 1 || j == 0) return 0;
if (i == N + 1) return 1;
if (emeo[i][j] != -1) return emeo[i][j];
int life = set.contains(i) ? j - 1 : j;
emeo[i][j] = backtrack(i + 1, life)
+ backtrack(i + 2, life)
+ backtrack(i + 3, life);
return emeo[i][j];
}
// dp
public int f2(int M, int N, int K, int[] L) {
Set<Integer> set = new HashSet<>();
for (int i : L) set.add(i);
// dp[i][j] 表示「在位置 i,还剩 j 条命」的通关走法个数
int[][] dp = new int[N + 2][M + 1];
// base case:在位置 0,通关走法个数为 1
// dp[0][0 ... M - 1] = 0,因为 这些情况都是不存在的!!
dp[0][M] = 1;
for (int i = 1; i <= N + 1; i++) {
for (int j = 1; j <= M - (set.contains(i) ? 1 : 0); j++) {
int life = set.contains(i) ? j + 1 : j;
for (int k = 1; k <= 3 && i - k >= 0; k++) {
dp[i][j] += dp[i - k][life];
}
}
}
int ans = 0;
for (int i = 1; i <= M; i++) ans += dp[N + 1][i];
return ans;
}
// dp「AC 代码」
public int f3(int M, int N, int K, int[] L) {
Set<Integer> set = new HashSet<>();
for (int i : L) set.add(i);
int[][] dp = new int[N + 2][M + 1];
dp[0][M] = 1;
for (int i = 1; i <= N + 1; i++) {
boolean trap = set.contains(i);
int t = trap ? 1 : 0;
for (int j = 1; j <= M - t; j++) {
if (i >= 1) {
if (trap) dp[i][j] += dp[i - 1][j + 1];
else dp[i][j] += dp[i - 1][j];
}
if (i >= 2) {
if (trap) dp[i][j] += dp[i - 2][j + 1];
else dp[i][j] += dp[i - 2][j];
}
if (i >= 3) {
if (trap) dp[i][j] += dp[i - 3][j + 1];
else dp[i][j] += dp[i - 3][j];
}
}
}
return Arrays.stream(dp[N + 1]).sum();
}
public static void main(String[] args) {
Bridge bridge = new Bridge();
Random random = new Random();
// 造数据
for (int i = 0; i < 100; i++) {
int M = random.nextInt(5) + 1, N = random.nextInt(32) + 1, K = random.nextInt(N) + 1;
int[] broken = new int [K];
Set<Integer> set = new HashSet<>();
int cnt = 0;
while (cnt < K) {
int cur = random.nextInt(N) + 1;
if (set.contains(cur)) continue;
set.add(cur);
broken[cnt++] = cur;
}
// System.out.println(M + "--" + N + "--" + K);
// System.out.println(Arrays.toString(broken));
int r1 = bridge.f1(M, N, K, broken);
int r2 = bridge.f2(M, N, K, broken);
int r3 = bridge.f3(M, N, K, broken);
System.out.println((r1 == r2 && r1 == r3) + "--" + r1 + "--" + r2 + "--" + r3);
}
}
}
有一批数据包需要传输,每个数据包大小不一样,传输需要不同的时长,现在有N个传输通道,每个通道的大小也不一样,通道只能传输小于等于自己大小的数据包,不同通道可以同时传输数据包,通道中可以缓存多个数据包,当新任务来时,可以先进入缓存队列等待发送,问最短需要多长时间能够传输完成,通道会确保所有数据包都可以传输
解答要求
时间限制: C/C++ 1500ms,其他语言: 3000ms 内存限制: C/C++ 256MB,其他语言: 512MB
输入
第一行MN, M表示队列长度,N表示传输通道数第二行有N个数,表示每个通道的大小P 第三行有M个数,表示每个数据包的大小Q第四行有M个数,表示每个数据包传输时长S 1 <=M,S, P, Q <= 10000 1 <=N <= 1000
输出
输出传输完所有数据包需要的最短时长
样例1
输入: 5 2 5 3 1 4 5 2 3 1 6 10 3 4 输出:16 解释:数据包3进入通道1,数据包2进入通道1,输数据包5进入通道2,数据句4进入通道2,数据包1讲入通道2:通道1的传输时长是10+6=16,通道2的传输时长是3+2+1=8,这样最短时长就为16
样例2
输入:3 2 6 13 2 11 5 3 25 14 输出:25 解释:数据包2进入通道2数据包3进入通道1数据包1进入通道1:通道1的传输时长是14+3=17,通道2的传输时长是25,这样最短时长就为25
贪心策略一:按照数据包大小递减排序,处于同一区间的数据包按照时间递减排序
贪心策略二:按照数据包传输时间递减排序,时间相同,按照数据包大小递减排序,如果有多个通道结束时间相同,选择更小的通道
坑:大小和时间成正比
xxxxxxxxxx
public class Transition {
// 贪心策略一
public int f1(int M, int N, int[] P, int[] Q, int[] S) {
Integer[] idx = IntStream.range(0, M).boxed().toArray(Integer[]::new);
Arrays.sort(idx, (a, b) -> Integer. compare(Q[b], Q[a]));
Arrays.sort(P);
List<Integer> list = new ArrayList<>();
List<Integer>[] lists = new ArrayList[N];
for (int i = 0; i < N; i++) lists[i] = new ArrayList<>();
for (int i = N - 1, j = 0; i >= 0; i--) {
// 通道的上下界
int lo = i == 0 ? 0 : P[i - 1], hi = P[i];
// 按照通道分组
while (j < idx.length && lo < Q[idx[j]] && Q[idx[j]] <= hi) lists[N - i - 1].add(idx[j++]);
// 组内排序
lists[N - i - 1].sort((a, b) -> S[b] - S[a]);
// 合并分组
list.addAll(lists[N - i - 1]);
}
// for (int i = 0; i < list.size(); i++) {
// System.out.println(Q[list.get(i)] + "--" + S[list.get(i)]);
// }
Queue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
int cnt = N - 1;
for (int i = 0; i < M; i++) {
if (cnt >= 0 && Q[list.get(i)] <= P[cnt]) {
pq.offer(new int[]{P[cnt--], 0});
}
int[] cur = pq.poll();
cur[1] += S[list.get(i)];
pq.offer(cur);
}
int ans = 0;
while (!pq.isEmpty()) {
int[] cur = pq.poll();
ans = Math.max(ans, cur[1]);
}
return ans;
}
// 贪心策略二
public int f2(int M, int N, int[] P, int[] Q, int[] S) {
Integer[] idx = IntStream.range(0, M).boxed().toArray(Integer[]::new);
Arrays.sort(idx, (a, b) -> {
// 先根据时间排序
if (S[a] != S[b]) return S[b] - S[a];
return Q[b] - Q[a]; // 再根据大小排序
});
Arrays.sort(P);
int[] time = new int[N];
for (int i = 0; i < M; i++) {
int curQ = Q[idx[i]], curS = S[idx[i]];
// 挑选出最优通道:能处理该数据包的最小通道
Queue<Integer> pq = new PriorityQueue<>((a, b) -> {
if (time[a] != time[b]) return time[a] - time[b];
else return P[a] - P[b];
});
// 将所有可能处理该数据包的通道加入队列
for (int j = N - 1; j >= 0 && curQ <= P[j]; j--) pq.offer(j);
time[pq.poll()] += curS;
}
int ans = 0;
for (int i = 0; i < N; i++) ans = Math.max(ans, time[i]);
return ans;
}
// 贪心策略二「AC 代码」
public int f3(int M, int N, int[] P, int[] Q, int[] S) {
Arrays.sort(P);
int[] times = new int[N];
Queue<Integer> idx = new PriorityQueue<>((a, b) -> {
// 先根据时间排序
// if (S[a] != S[b]) return S[b] - S[a];
// return Q[b] - Q[a]; // 再根据大小排序
if (Q[a] != Q[b]) return Q[b] - Q[a];
else return S[b] - S[a];
});
for (int i = 0; i < M; i++) idx.offer(i);
while (!idx.isEmpty()) {
int i = idx.poll();
int large = Q[i];
int cost = S[i];
int min = Integer.MAX_VALUE;
int min_p = -1;
Queue<Integer> ch = new PriorityQueue<>((a, b) -> {
if (times[a] == times[b]) return P[a] - P[b];
else return times[a] - times[b];
});
for (int j = N - 1; j >= 0 && P[j] >= large; j--) ch.offer(j);
times[ch.poll()] += cost;
}
int ans = 0;
for (int i = 0; i < N; i++) ans = Math.max(ans, times[i]);
return ans;
}
public int f4(int M, int N, int[] P, int[] Q, int[] S) {
Integer[] idx = new Integer[M];
for (int i = 0; i < M; i++) idx[i] = i;
Arrays.sort(idx, (a, b) -> {
if (Q[a] != Q[b]) return Q[b] - Q[a];
else return S[b] - S[a];
});
// Queue<int[]> pq = new PriorityQueue<>((a, b) -> {
// if (a[1] != b[1]) return a[1] - b[1];
// else return a[0] - b[0];
// });
Queue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
Arrays.sort(P);
int cnt = N - 1;
for (int i = 0; i < M; i++) {
if (cnt >= 0 && Q[idx[i]] <= P[cnt]) {
pq.offer(new int[]{P[cnt--], 0});
}
int[] cur = pq.poll();
cur[1] += S[idx[i]];
pq.offer(cur);
}
int ans = 0;
while (!pq.isEmpty()) {
int[] cur = pq.poll();
ans = Math.max(ans, cur[1]);
}
return ans;
}
public int f5(int M, int N, int[] P, int[] Q, int[] S) {
Integer[] idx = IntStream.range(0, M).boxed().toArray(Integer[]::new);
Arrays.sort(idx, (a, b) -> {
if (Q[a] != Q[b]) return Q[b] - Q[a];
else return S[b] - S[a];
});
Queue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
Arrays.sort(P);
int cnt = N - 1;
pq.offer(new int[]{P[cnt--], 0});
for (int i = 0; i < M; i++) {
if (cnt >= 0 && Q[idx[i]] <= P[cnt]) {
pq.offer(new int[]{P[cnt--], 0});
}
int[] cur = pq.poll();
cur[1] += S[idx[i]];
pq.offer(cur);
}
int ans = 0;
while (!pq.isEmpty()) {
int[] cur = pq.poll();
ans = Math.max(ans, cur[1]);
}
return ans;
}
public static void main(String[] args) {
Transition transition = new Transition();
int sz = 100000;
Random random = new Random();
for (int i = 0; i < 10000; i++) {
int M = random.nextInt(sz) + 1, N = random.nextInt(1000) + 1;
int[] P = new int[N];
int cnt = 0, max = 0;
Set<Integer> set = new HashSet<>();
while (cnt < N) {
int cur = random.nextInt(sz) + 1;
if (set.contains(cur)) continue;
set.add(cur);
P[cnt++] = cur;
max = Math.max(max, cur);
}
int[] Q = new int[M], S = new int[M];
cnt = 0;
while (cnt < M) {
Q[cnt] = random.nextInt(max) + 1;
S[cnt] = (int) (Q[cnt] * 0.9) + 10;
// S[cnt] = random.nextInt(max) + 1;
cnt++;
}
int r1 = transition.f1(M, N, Arrays.copyOf(P, N), Arrays.copyOf(Q, M), Arrays.copyOf(S, M));
int r2 = transition.f2(M, N, Arrays.copyOf(P, N), Arrays.copyOf(Q, M), Arrays.copyOf(S, M));
int r3 = transition.f3(M, N, Arrays.copyOf(P, N), Arrays.copyOf(Q, M), Arrays.copyOf(S, M));
int r4 = transition.f4(M, N, Arrays.copyOf(P, N), Arrays.copyOf(Q, M), Arrays.copyOf(S, M));
int r5 = transition.f5(M, N, Arrays.copyOf(P, N), Arrays.copyOf(Q, M), Arrays.copyOf(S, M));
System.out.println((r1 == r2 && r1 == r3 && r1 == r4 && r1 == r5) + "--" + r1 + "--" + r2 + "--" + r3 + "--" + r4 + "--" + r5);
}
}
}