Problem 2185 树的路径覆盖
Accept: 69 Submit: 193
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
2170 0 1 1 2 2
Sample Outpute
0 02 3
边可以被重复覆盖 最优情况就是每条路径经过了两个叶子节点 所以路径数=(叶子节点个数+1)/2
边不可以重复覆盖 看一个节点有几个子节点 可以用一条路径来覆盖两个子节点
注意到 如果一个节点有祖父节点 这个节点可以由祖父节点与父亲节点之间的边延长下来得到覆盖
如果该节点是根节点 还是(num+1)/2
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>
#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 100010
#define MAXM 100010
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
using namespace std;
int Read()
{
char ch;
int a = 0;
while((ch = getchar()) == ' ' | ch == '\n');
a += ch - '0';
while((ch = getchar()) != ' ' && ch != '\n')
{
a *= 10;
a += ch - '0';
}
return a;
}
void Print(int a) //输出外挂
{
if(a>9)
Print(a/10);
putchar(a%10+'0');
}
struct Edge
{
int v,next;
}edge[2*MAXN];
int head[MAXN],tot;
int vis[MAXN];
int deg[MAXN];
int ans1,ans2;
void addedge(int u,int v)
{
edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++;
}
void init()
{
MEM(vis,0); MEM(head,-1); MEM(deg,0);
tot=0;
}
void dfs(int u)
{
vis[u]=1;
int num=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(vis[v]) continue;
dfs(v);
num++;
}
if(u==0) num++;
ans2+=num/2;
}
int main()
{
//fread;
int n;
int tc;
scanf("%d",&tc);
while(tc--)
{
scanf("%d",&n);
init();
for(int i=1;i<n;i++)
{
int v;
scanf("%d",&v);
addedge(i,v);
addedge(v,i);
deg[i]++; deg[v]++;
}
ans1=ans2=0;
for(int i=0;i<n;i++)
{
if(deg[i]==1)
ans1++;
}
ans1++;
ans1/=2;
dfs(0);
printf("%d %d\n",ans1,ans2);
}
return 0;
}