题目如下,我自己还设计了两个测试样例,样例都通过了,但是提交一直RE,求大神指导。
我的思路是:
1. 从最底层叶子节点开始寻找兄弟节点,然后将多个兄弟节点合并成1个(比如讲6的父节点记作-5,并将6从叶子节点中删除,同时更新距离矩阵);
2. 当最底层所有的兄弟节点都合并完成之后,那么合并的集合跟上一层的非叶子节点是一一对应的;
3. 然后从左到右依次给叶子节点分配父节点,并进行子节点与父节点的合并(给底层叶子节点赋值,将父节点变成叶子节点,更新叶子节点数组与距离矩阵(即所有非0的距离都减1),并将树的层数减1)
4. 当树的深度变成1时,就结束,得到答案
题目给的
8 3 5
1 3 4
1
2 3 4
5 6 7 8
3 5 6 7 8
0 3 3 3 3
3 0 2 4 4
3 2 0 4 4
3 4 4 0 2
3 4 4 2 0
设计1
11 3 7
1 4 6
1
2 3 4 5
6 7 8 9 10 11
4 6 7 8 9 10 11
0 3 3 3 3 3 3
3 0 2 4 4 4 4
3 2 0 4 4 4 4
3 4 4 0 2 4 4
3 4 4 2 0 4 4
3 4 4 4 4 0 2
3 4 4 4 4 2 0
设计2
9 4 4
1 2 4 2
1
2 3
4 5 6 7
8 9
6 7 8 9
0 2 5 5
2 0 5 5
5 5 0 4
5 5 4 0
import java.util.Scanner;
public class Main {
private static int N, M, K;
private static int[] A, leaves, parents;
private static int[][] depth, dis;
public static void main(String[] args) {
init();
getAnswer();
for (int i = 1; i <= N; i++)
System.out.print(parents[i] + " ");
}
//求解函数
private static void getAnswer() {
int i, j, leavesIndex, brotherNum;
int[] brothers = new int[100];
while (M > 1) {//当深度==1,停止
for (i = 0; i < A[M]; i++) {
brotherNum = 0;
leavesIndex = nodeToleavesIndex(depth[M][i]);
if (leavesIndex == 101) continue;
for (j = 0; j < K; j++) {
if (dis[leavesIndex][j] == 2)
brothers[brotherNum++] = leavesIndexToNode(j);
}
if (brotherNum > 0)
mergeBrothers(brothers, brotherNum, depth[M][i]);
}
mergeLastTwoLayers();
M--;
}
}
// 合并最后两层
private static void mergeLastTwoLayers() {
int i, j, length = 0, brother;
int[] parentNodes = new int[100];
//找出上一层中的所有非叶子节点
for (i = 0; i < A[M - 1]; i++)
if (!isLeaves(depth[M - 1][i]))
parentNodes[length++] = depth[M - 1][i];
j = 0;
for (i = 0; i < A[M]; i++) {
if (parents[depth[M][i]] == 101) {
parents[depth[M][i]] = parentNodes[j];
updateParent(parentNodes[j], depth[M][i]);
j++;
} else {
brother = 0 - parents[depth[M][i]];
parents[depth[M][i]] = parents[brother];
}
}
}
//父子节点合并之后的更新操作
private static void updateParent(int parentNode, int node) {
int i, leavesIndex;
leavesIndex = nodeToleavesIndex(node);
leaves[leavesIndex] = parentNode;
for (i = 0; i < K; i++) {//更新距离,由于父节点到了上一层,因此将原节点到其他叶子节点的距离减1
if (dis[leavesIndex][i] != 0) dis[leavesIndex][i]--;
if (dis[i][leavesIndex] != 0) dis[i][leavesIndex]--;
}
}
//是否是叶子节点
private static boolean isLeaves(int node) {
for (int i = 0; i < K; i++)
if (node == leaves[i]) return true;
return false;
}
//合并兄弟节点
private static void mergeBrothers(int[] brothers, int brotherNum,
int thisNode) {
int i;
for (i = 0; i < brotherNum; i++) {
parents[brothers[i]] = 0 - thisNode;//将该节点的父节点记录为兄弟节点编号的负数
updateBrothers(brothers[i]);
}
}
//根据节点编号查找在叶子节点中的位置,因为距离矩阵记录的是叶子节点中的位置之间的关系
private static int nodeToleavesIndex(int node) {
for (int i = 0; i < K; i++)
if (node == leaves[i]) return i;
return 101;
}
//根据在叶子节点中的位置,找到对应的节点编号
private static int leavesIndexToNode(int leavesIndex) {
return leaves[leavesIndex];
}
// 兄弟节点合并之后的更新
private static void updateBrothers(int node) {
int i, j;
int leavesIndex = nodeToleavesIndex(node);
//下面两个for循环用来删除该节点在距离矩阵中的关系
for (i = leavesIndex; i < K - 1; i++)
for (j = 0; j < K; j++) {
dis[i][j] = dis[i + 1][j];
}
for (i = leavesIndex; i < K - 1; i++)
for (j = 0; j < K; j++) {
dis[j][i] = dis[j][i + 1];
}
//这个for循环将该节点从叶子节点中删除
for (i = leavesIndex; i < K - 1; i++)
leaves[i] = leaves[i + 1];
K--;//叶子节点数量减1
}
private static void init() {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
K = sc.nextInt();
A = new int[M + 1];
parents = new int[N + 1];
leaves = new int[K];
depth = new int[M + 1][100];
dis = new int[K][K];
int i, j;
for (i = 1; i <= N; i++)
parents[i] = 101;
parents[1] = 0;
for (i = 1; i <= M; i++)
A[i] = sc.nextInt();
for (i = 1; i <= M; i++) {
for (j = 0; j < A[i]; j++) {
depth[i][j] = sc.nextInt();
}
}
for (i = 0; i < K; i++)
leaves[i] = sc.nextInt();
for (i = 0; i < K; i++)
for (j = 0; j < K; j++)
dis[i][j] = sc.nextInt();
}
}