题目链接:http://acm.fzu.edu.cn/problem.php?pid=2185
题意:给定一个树,分别求出允许重覆盖与不能重覆盖的最小路径数。
思路:
第一:当允许重覆盖时,显然路径数为:(叶子数+1)/2。
第二:当不允许重覆盖时,我们从一个叶子开始深搜,每到一个新结点,要使路径数最小,则必须从这个结点继续往下走,也就是说,这个结点的度实际上减少了两个,假设这个结点的度为3,在原有的基础上,路径数还需要增加1,仔细思考可以的出:每到一个新结点,则需要增加的路径数为:(该结点的度数-1)/2。
代码:
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
vector<int> v[100010];
int vis[100010];
int dfs(int n){
if((int)v[n].size()==1) return 0;
int sum=((int)v[n].size()-1)/2;
for(int i=0;i<(int)v[n].size();i++)
if(!vis[v[n][i]]) vis[v[n][i]]=1,sum+=dfs(v[n][i]);
return sum;
}
int main(){
int n;int T;cin>>T;
while(T--){
while(cin>>n)
{
for(int i=0;i<=n;i++) v[i].clear();
memset(vis,0,sizeof(vis));
for(int i=0;i<n-1;i++){
int t;scanf("%d",&t);
v[t].push_back(i+1);
v[i+1].push_back(t);
}
int cnt=0;int op=-1;
for(int i=0;i<n;i++)//寻找叶子数
if((int)v[i].size()==1) cnt++,op=i;
int sum=0;
if(op!=-1){//从任意一叶子开始深搜
vis[v[op][0]]=1;
sum=dfs(v[op][0]);
sum+=1;//加上第一条路径
}
cout<<(cnt+1)/2<<" "<<sum<<endl;
}
}
return 0;
}