CF981C Useful Decomposition【树/思维】

【链接】:CF
【题意】:给定一棵树,要求拆成若干条简单路径,并且这些路径都经过一个公共节点。给出任意一个解决方案,如不存在输出No。
【分析】:

因为是一棵树, 所以如果要求任意两条路线至少有一个公共点, 到最后, 所有的路线都会有唯一的公共点. 如果有两个公共点的话, 就至少有两条路线只包含其中的一条路线, 否则就会有环, 有了环就不是树了.

也就是说, 所有的点, 除了那个唯一的公共点, 必须度数小于  2 .

在所有点之中:

度数为  1 的点是路线的一个端点.
度数为  2 的是一条路线中除了两端以外的点.
度数大于  2 的是路线的公共点. 如果有两个及以上的点的度数是大于  2 的, 代表不可能路线中任意两条至少交于一点, 输出 No.
如果没有度数大于  2 的点, 代表只有一条路线.
如何输出路线:

先输出 Yes, 代表可以将树分解.
接着输出路线的个数, 也就是度数为  1 的点的个数.
接着, 对于每条路线, 输出其中一个度数为  1 的点和 唯一的 公共点.
注意: 如果没有度数大于 2  的点, 代表只有一条路线, 此时路线个数并不等于度数为 1 的点的个数, 并且端点就是两个度数为  1 的点.

【代码】:

#include <bits/stdc++.h>

using namespace std;

int n;
int deg[100005]; // 每个点的度数
int leaves[100005], comv[100005]; // leaves 存储度数为 1 的端点, comv 存储公共点
int nleaf = 0, ncomv = 0; // 存储度数为 1 的点与公共点的数量
int x,y;
/*
有三种可能情况:
所有链在某一点上相交,也就是只有一个点度数>2;
只有一条链,就是两个点度数为1,其他点度数为2;
不符合要求的情况,就是有超过一个点度数>2
*/
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        deg[x]++,deg[y]++;
    }
    for(int i=1;i<=n;i++)
    {
        if(deg[i]==1) leaves[++nleaf]=i;
        else if(deg[i]>2) comv[++ncomv]=i;
    }
    //如果公共点不唯一, 就输出 "No"
    if(ncomv>1) {printf("No
");return 0;}//不符合要求的情况,就是有超过一个点度数>2
    
    printf("Yes
");
    // 如果只有一条路线, 就输出两端 (即两个度数为 1 的点)
    if(ncomv==0) printf("1
%d %d
",leaves[1],leaves[2]);//只有一条链,就是两个点度数为1,其他点度数为2;
    
    else//所有链在某一点上相交,也就是只有一个点度数>2;
    {
        printf("%d
",nleaf);//度数为1的点的个数
        for(int i=1;i<=nleaf;i++)
        {
            printf("%d %d
",comv[1],leaves[i]);//公共点与一个度数为1的点
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Roni-i/p/9130116.html