题目会做但是做不全对
一、多米诺骨牌
在一维平面上,存放着N个多米诺骨牌,每个骨牌有两个属性:位置,高度。
输入M个查询,每个查询为一个整数x,问推一下第x个骨牌,会有多少个骨牌倒下去
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
class Node {
int x, h, index;
int can;
Node(int x, int h, int index) {
this.x = x;
this.h = h;
this.index = index;
}
}
Main() {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
Node[] a = new Node[n];
for (int i = 0; i < n; i++) {
a[i] = new Node(cin.nextInt(), cin.nextInt(), i);
}
Arrays.sort(a, Comparator.comparingInt(x -> x.x));
for (int i = a.length - 1; i >= 0; i--) {
a[i].can = 1;
for (int j = i + 1; j < a.length; j++) {
if (a[i].x + a[i].h <= a[j].x) break;
a[i].can = Math.max(a[i].can, a[j].can + j - i);
}
}
Arrays.sort(a, Comparator.comparingInt(x -> x.index));
System.out.print(a[0].can);
for (int i = 1; i < a.length; i++) {
System.out.print(" " + a[i].can);
}
}
public static void main(String[] args) {
new Main();
}
}
二、最近公共祖先
在族谱上,存储着父子对,输入n对父子关系,如
子1 父1
子2 父2
.....
输入M个查询,每个查询包含A和B两个数字。如果A是B的祖先,输出1;如果B是A的祖先,输出2;否则,输出0。
这个问题很显然是经典的最近公共祖先问题LCA。以空间换时间,倍增算法。
import java.util.Scanner;
public class Main {
int[][] father;
int[] level;
int lca(int A, int B) {
if (A == B) return A;
if (level[A] == level[B]) {
if (father[A][0] == father[B][0]) return father[A][0];
for (int i = father[0].length - 1; i >= 0; i--) {
if (father[A][i] == father[B][i]) continue;
return lca(father[A][i], father[B][i]);
}
}
if (level[A] > level[B]) {
int tem = A;
A = B;
B = tem;
}
int i = father[0].length - 1;
while ((1 << i) > level[B] - level[A]) {
i--;
}
B = father[B][i];
return lca(A, B);
}
int getLevel(int x) {
if (father[x][0] == -1) return 1;
if (level[x] != -1) return level[x];
int i = father[0].length - 1;
while (father[x][i] == -1) i--;
level[x] = (1 << i) + getLevel(father[x][i]);
return level[x];
}
Main() {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int layer = 17;
father = new int[n + 1][layer];
level = new int[n + 1];
for (int i = 0; i < father.length; i++) {
for (int j = 0; j < father[i].length; j++) {
father[i][j] = -1;
}
}
for (int i = 0; i < n; i++) {
father[cin.nextInt()][0] = cin.nextInt();
}
for (int i = 1; i < layer; i++) {
for (int j = 1; j <= n; j++) {
if (father[j][i - 1] == -1) {
father[j][i] = -1;
} else {
father[j][i] = father[father[j][i - 1]][i - 1];
}
}
}
for (int i = 0; i < level.length; i++) {
level[i] = -1;
}
for (int i = 1; i <= n; i++) {
level[i] = getLevel(i);
}
int m = cin.nextInt();
for (int i = 0; i < m; i++) {
int A = cin.nextInt(), B = cin.nextInt();
int anc = lca(A, B);
if (anc == A) {
System.out.println(1);
} else if (anc == B) {
System.out.println(2);
} else {
System.out.println(0);
}
}
}
public static void main(String[] args) {
new Main();
}
}
三、按几次键才能变换数字
给定一个int,你只能对它执行两种操作:乘以2,减一。
输入两个int值N和M,问需要多少次操作才能从N变成M?
如果N>M,那么需要N-M次操作无疑。
如果N<M,那么至少需要ceil(log2(N/M))次,然后开始做减法。与其需要做这么多次减法,就不如把这些减法在乘2之前进行。
import java.util.PriorityQueue;
import java.util.Random;
public class Main {
int maxn = 1 << 7;
int[][] a = new int[maxn][maxn];
void init() {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
a[i][j] = maxn * 2;
}
a[i][i] = 0;
}
for (int i = 1; i < maxn; i++) {
PriorityQueue<Integer> q = new PriorityQueue<>();
q.add(i);
while (!q.isEmpty()) {
int j = q.poll();
if (j >= maxn) continue;
if (j * 2 < maxn) {
if (a[i][j * 2] > a[i][j] + 1) {
q.add(j * 2);
a[i][j * 2] = a[i][j] + 1;
}
}
if (j - 1 > 0) {
if (a[i][j - 1] > a[i][j] + 1) {
q.add(j - 1);
a[i][j - 1] = a[i][j] + 1;
}
}
}
}
}
int solve(int n, int m) {
if (n == m) return 0;
if (n > m) {
return n - m;
}
int miCount = (int) Math.ceil(Math.log(m * 1.0 / n) / Math.log(2));
int p = n * (1 << miCount);
if (p == m) return miCount;
int sub = (p - m) / (1 << miCount);
if (sub == 0) return solve(n * 2, m) + 1;
return solve(n - sub, m) + sub;
}
Main() {
Random r = new Random();
init();
for (int i = 0; i < 100; i++) {
int n = r.nextInt(maxn - 1) + 1, m = r.nextInt(maxn - 1) + 1;
System.out.println(n + " " + m + " " + solve(n, m) + " " + a[n][m]);
}
}
public static void main(String[] args) {
new Main();
}
}