题目:http://acm.fzu.edu.cn/problem.php?pid=2185
题意:n个点n-1条边, 用最少的路径去覆盖所有的边, 求(1)允许边被重复覆盖, (2)不允许边被重复覆盖.
分析:(1)可重复覆盖的话,总会由叶子节点走到另外一个叶子节点,路径数就是结子节点的数目n/2向上取整,n==1时特判。(2)和(1)一样由叶子节点走到叶子节点,不过走过的线路要删掉,同时会产生新的叶子节点,用一个队列存放叶子节点,然后直接由叶子节点推到另外一个叶子节点.
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
#define MAXN 100005
queue <int > leaf;
struct node1
{
int head;
int count;
};
struct node2
{
int value;
int next;
};
struct tree
{
node1 Table[MAXN];
node2 List[1000000];
int cnt;
void Clear()
{
cnt=0;
for(int i=0;i<MAXN;i++)
{
Table[i].count=0;
Table[i].head=-1;
}
}
void Insert(int a,int b)
{
List[cnt].value=b;
List[cnt].next=Table[a].head;
Table[a].head=cnt;
Table[a].count++;
cnt++;
List[cnt].value=a;
List[cnt].next=Table[b].head;
Table[b].head=cnt;
Table[b].count++;
cnt++;
}
void Delete(int a,int b)
{
int pos,per=-1;
pos=Table[a].head;
while(List[pos].value!=b)
{
per=pos;
pos=List[pos].next;
}
if(per==-1)
Table[a].head=List[pos].next;
else
List[per].next=List[pos].next;
Table[a].count--;
per=-1;
pos=Table[b].head;
while(List[pos].value!=a)
{
per=pos;
pos=List[pos].next;
}
if(per==-1)
Table[b].head=List[pos].next;
else
List[per].next=List[pos].next;
Table[b].count--;
}
}T;
int Find()
{
while(!leaf.empty() && T.Table[leaf.front()].count!=1)
leaf.pop();
if(leaf.empty())
return -1;
else
return leaf.front();
}
int main()
{
int n,i,j,x,cnt,ans,cur,pos1,pos2,temp;
int Tcase;
scanf("%d\n",&Tcase);
while(Tcase--)
{
scanf("%d",&n);
ans=cnt=0;
T.Clear();
while(!leaf.empty())
leaf.pop();
for(i=1;i<=n-1;i++)
{
scanf("%d",&x);
T.Insert(x,i);
}
// for(i=0;i<=n-1;i++)
// {
// int temp=T.Table[i].head;
// printf("%d count(%d):",i,T.Table[i].count);
// while(temp!=-1)
// {
// printf("%d ",T.List[temp].value);
// temp=T.List[temp].next;
// }
// printf("\n");
// }
for(i=0;i<=n-1;i++)
{
if(T.Table[i].count==1)
{
cnt++;
leaf.push(i);
}
}
while((cur=Find())!=-1)
{
ans++;
while(1)
{
pos1=cur;
temp=T.Table[pos1].head;
pos2=T.List[temp].value;
T.Delete(pos1,pos2);
cur=pos2;
if(T.Table[pos1].count==1)
leaf.push(pos1);
if(T.Table[pos2].count==1)
leaf.push(pos2);
if(T.Table[cur].count==0)
break;
}
}
if(cnt==1)
printf("0 %d\n",ans);
else
printf("%d %d\n",(cnt+2-1)/2,ans);
}
return 0;
}