#1490 : Tree Restoration-(微软2017在线笔试)

输入
n m k
m个数,表示每层的节点个数
接下来m行是每层的节点,节点顺序是从左往右的
k个叶子节点
k*k个矩阵,表示叶子节点之间的距离

输出:
每个节点的父亲节点编号,root节点是0

题解:
1.很明显,相邻两个节点的距离如果是2,那么便是同一个父亲节点。
2.第一个点的父亲节点u,必定是上一层第一个非叶子节点fa
3.u左边的节点v
如果dis[u][v]==2,则fa[v]=fa[u]
否则,fa[v]为fa的下一个非叶子节点
所以很明显,dis矩阵得为n*n的大小,而不仅仅是k*k
4.由于一开始只知道各叶子节点之间的dis,所以从底层往上推。
每次求该层节点的父亲节点,同时更新上面一层的相邻节点的距离


一开始WA的原因是更新父节点的距离时,只更新了其到其它叶子节点的距离,没有更新到所有点的距离。。。
所以遇到下面的样例时候,dis[3][4]=-2,而不是2
1->2
2->3,2->4
3->5,3->6 4->7
5->8,5->9 6->10 7->11
11 5 4
1 1 2 3 4
1
2
3 4
5 6 7
8 9 10 11
8 9 10 11
0 2 4 6
2 0 4 6
4 4 0 6
6 6 6 0

错误的输出:0 1 2 0 3 3 4 5 5 6 7
正确的输出:0 1 2 2 3 3 4 5 5 6 7

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
using namespace std;
const int maxn=105;
int n,m,k;
int depth[maxn]; //每层的节点个数
int layer[maxn][maxn]; //每层的节点
int fa[maxn]; //ans
int leaves[maxn]; //叶子节点
int isleaves[maxn]; //是否为叶子节点
int dis[maxn][maxn];
int son[maxn]; //父亲节点的随便其中一个儿子就行,因为点u到fa的所有儿子的距离都一样
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    memset(isleaves,0,sizeof(isleaves));
    memset(son,0,sizeof(son));
    memset(dis,0,sizeof(dis));

    for(int i=0;i<m;i++){
        scanf("%d",&depth[i]);
    }
    for(int i=0;i<m;i++){
        for(int j=0;j<depth[i];j++){
            scanf("%d",&layer[i][j]);
        }
    }
    for(int i=0;i<k;i++){
        scanf("%d",&leaves[i]);
        isleaves[leaves[i]]=1;
    }
    for(int i=0;i<k;i++){
        for(int j=0;j<k;j++){
            scanf("%d",&dis[leaves[i]][leaves[j]]);
        }
    }
    fa[layer[0][0]]=0;
    for(int i=0;i<depth[1];i++)
        fa[layer[1][i]]=layer[0][0];
    for(int i=m-1;i>=2;i--){
        int point=0;//i-1层中第一个不是叶子节点的节点,必定是当前节点的父亲
        while(isleaves[layer[i-1][point]] && point<depth[i-1]){
            point++;
        }
        int u=layer[i][0];
        fa[u]=layer[i-1][point];
        son[layer[i-1][point]]=u;
        //不能只更新父节点到其它叶子节点的距离,而是到其它所有点的距离
        for(int kk=0;kk<n;kk++){
            if(dis[u][kk]>0){
                dis[fa[u]][kk]=dis[kk][fa[u]]=dis[u][kk]-1;
            }
        }
        for(int kk=0;kk<k;kk++){
            dis[leaves[kk]][fa[u]]=dis[fa[u]][leaves[kk]]=dis[leaves[kk]][u]-1;
        }
        for(int j=1;j<depth[i];j++){
            int v=layer[i][j];
            //如果和上一个节点u距离为2,说明父亲节点是同一个
            if(dis[u][v]==2){
                fa[v]=fa[u];
            }
            //否则,父亲节点是i-1层中下一个不是叶子节点的节点
            else {
                point++;
                while(isleaves[layer[i-1][point]] && point<depth[i-1]){
                    point++;
                }
                fa[v]=layer[i-1][point];
                son[layer[i-1][point]]=v;
                //更新父亲节点到其它节点的距离
                for(int kk=0;kk<n;kk++){
                    if(dis[v][kk]>0){
                        dis[fa[v]][kk]=dis[kk][fa[v]]=dis[v][kk]-1;
                    }
                }
            }
            u=v;
        }
        //更新i-1层相邻节点的距离
        for(int kk=0;kk<depth[i-1]-1;kk++){
            int na=layer[i-1][kk];
            int nb=layer[i-1][kk+1];
            int sona,sonb;
            /*只要有一方是叶子节点,那么dis已经有了
              如果都不是,那么就是对应儿子节点之间的距离-1
              因为是从底层往上推的,所以儿子所在那一层的相邻节点距离已经更新过了。
            */
            if(!isleaves[na] && !isleaves[nb]){
                sona=son[na];
                sonb=son[nb];
                dis[na][nb]=dis[nb][na]=dis[sona][sonb]-2;
            }
        }
    }
    printf("%d",fa[1]);
    for(int i=2;i<=n;i++){
        printf(" %d",fa[i]);
    }
    //printf("
");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/chenxiwenruo/p/6675159.html