hihoCoder #1490 Tree Restoration 一直RE,求指导

题目如下,我自己还设计了两个测试样例,样例都通过了,但是提交一直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();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值