zzulioj 1900(985的“树”难题)

985的“树”难题

Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 30 Solved: 7

SubmitStatusWeb Board
Description

985给你一棵“树”以及它的根节点,要求你先判定它是否是一棵树,其次他想知道每个节点的“太子”数目以及它的父亲(root的话输出自己)。
“太子判定条件”:
一、若x是y的孩子节点,那么x是y的“太子”;
二、若x是y的“太子”且y是z的“太子”,那么x是z的“太子”。
Input

第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入两个整数n,root分别代表树的节点数目以及根节点的编号。
接下来n-1行,每行输出两个整数u,v代表u节点和v节点之间有一条树边。
注:1 <= t <= 20,1 <= n <= 1e4,1 <= root <= n,1 <= u,v <= n。
Output

对每一组数据,若给定的“树”不合法输出NO即可,反之输出YES,接下来输出占两行:
第一行输出n个整数代表每个节点的“太子”数目,
第二行输出n个整数代表每个节点的父亲节点编号。
输出顺序从1到n,每两个数之间有一个空格,最后一个数后面没有空格。
Sample Input

2
3 1
1 2
2 3
2 1
1 1
Sample Output

YES
2 1 0
1 1 2
NO

听学长讲完再看着同学的代码敲出来,仔细回想一下也不算太难(呵呵),总体来说思路是这个样子的:先用dfs加上邻接表(总是感觉这两个东西以后用处很大的样子)连接一下父子节点,由于是n个点n-1条边所以不用考虑重边什么的,直接find函数找一下看看是不是每个点的祖先都是root,这里说明一下,用find函数的时候,只要没有压缩路径,那么父子节点是不会改变的,于是可以利用这个做一些有趣的事情(嘿嘿嘿~),比如说从i=1 —> i=n;遍历一遍(只有这样的时候)之后可以用num【】记录每个点的儿子个数;具体实现如下

#include 
#include 
#include 
#include 
using namespace std;
#define M 10010
#define INF 0x3f3f3f
#define RCL(a, b) memset(a, b, sizeof(a))

struct node
{
    int u, v, next;
};
node edge[M*2];
int edgenum, head[M*2], num[M], pre[M];
bool vis[M];
void addedge(int u, int v)
{
    node e = {u, v, head[u]};
    edge[edgenum] = e;
    head[u] = edgenum++;
}
int find(int a)
{
    int r = a;
    while(r != pre[r])
    {
        r = pre[r];
        num[r]++;
    }
    return r;
}
void init()
{
    RCL(head, -1);
    RCL(num, 0);
    edgenum = 0;
    RCL(vis, false);
}
void dfs(int u)
{
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v = edge[i].v;
        if(!vis[v])
        {
            pre[v] = u;//连接父子节点
            vis[v] = true;//连过的就不要再连了
            dfs(v);//深搜~深搜~
        }
    }
}
int main()
{
    int t, n, root, v, u, a, b;
    scanf("%d", &t);
    while(t--)
    {
        init();
        bool ok = true;
        scanf("%d%d", &n, &root);
        for(int i=1; iscanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        for(int i=0; i<=n; i++)
        {
            pre[i] = i;
        }
        vis[root] = true;
        dfs(root);//用dfs 加上临界表 把每个点与其父节点连上 
        for(int i=1; i<=n; i++)//遍历
        {
            if(find(i) != root)
            {
                ok = false;
                break;
            }
        }
        if(ok)
        {
            printf("YES\n");
            for(int i=1; i<=n; i++)
            {
                printf("%d", num[i]);
                if(i == n)
                    printf("\n");
                else
                    printf(" ");
            }
            for(int i=1; i<=n; i++)
            {
                printf("%d", pre[i]);
                if(i == n)
                    printf("\n");
                else
                    printf(" ");
            }
        }
        else
            printf("NO\n");
    }


    return 0;
}

你可能感兴趣的:(dfs,邻接表)