Problem 2185 树的路径覆盖
Accept: 113 Submit: 306
Time Limit: 2000 mSec Memory Limit : 32768 KB
Problem Description
給一棵树, 用最少的路径去覆盖所有的边, 求(1)允许边被重复覆盖, (2)不允许边被重复覆盖.
Input
第一行是组数T(T <= 20). 每组两行, 第一行是n(1 <= n <= 10^5), 第二行是n - 1个数(0-based), 第i个数x[i]表示有一条边(x[i], i + 1), (0 <= i <= n - 2).
Output
两个值,第一个值是允许边被重复覆盖情况下的答案,第二个值是不允许边被重复覆盖下的答案,用一个空格分隔.
Sample Input
2
1
7
0 0 1 1 2 2
Sample Output
0 0
2 3
Source
FOJ有奖月赛-2015年03月思路:
1、首先根据输入描述可知,这是一颗以0为根的树。那么接下来我们画出一个树的图形来观察:
此时我们考虑可以有重复边覆盖的问题,那么我们就是每次选择覆盖的路径为叶子节点1,---------------------根节点0----------------------叶子节点2的形式的路径。
那么我们不难发现,此种情况的解就是(叶子节点的个数+1)/2;
按照上图形式的方式排列节点,就是一种类似C的形状来选择覆盖路径(下图是一种路径覆盖的方式):
2、那么我们接下来考虑不能有边覆盖的情况:
①我们还是贪心,能画出来C就画C:子节点1--------------某根节点---------------子节点2
②那么如果画不出来C就画一。
枚举几种情况不难发现最终解为:节点0的出度+1/2和各个点的出度/2的累加和.
Ac代码:
#include<stdio.h>
#include<string.h>
using namespace std;
int out[100050];
int main()
{
int t;
scanf("%dd",&t);
while(t--)
{
int n;
scanf("%d",&n);
memset(out,0,sizeof(out));
for(int i=0;i<n-1;i++)
{
int x;
scanf("%d",&x);
out[x]++;
}
int cnt=0;
int output=0;
for(int i=0;i<n;i++)
{
if(out[i]==0&&i!=0)cnt++;
if(i==0)output+=(out[i]+1)/2;
else output+=out[i]/2;
}
printf("%d %d\n",(cnt+1)/2,output);
}
}