题目大意
给定一棵无根树,连接其中两个节点组成一条链,使树中的每一条边至少被一条链覆盖。 输出最少的链数量+其中任何一个解决方案。
解题思路
先引用原题的一个(水)测试样例:
5 <--节点数量
1 2 <--节点中连的边(节点数量-1条)
1 3
2 4
2 5
可以得到这样一颗树,我们可以用这样两条链覆盖它的所有边(解决方案不唯一)。
)
)
面对这种情况,应该怎么遍历呢?
部分代码+注解
先放部分代码,可能更方便理解思路。
先定义一个向量,记录与每个点有连边的节点,构造一棵简单的树。
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}接下来是开始dfs。先找到一个非叶节点,将其存储。
for(i=1;i<=n;i++)
if(v[i].size()>1)
{
dfs(i,i);
z=i;
break;
} 存储dfs到的每个叶节点,总数记录为t。
void dfs(int x,int y) //当前节点+父亲节点
{
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=y) dfs(v[x][i],x);
if(v[x].size()==1) t++,a[t]=x;
}通过 理 智 分 析,可以得出链的最多条数(tt)=叶节点个数/2(向上取整)
输出第L(i)和第L(t/2+i)两个叶节点连成一条链
(本来是想L(1)L(t),L(2)L(t-1)这样分组,但是会有例外)
这样1--3这条边就落单了
if(t%2==0) tt=t/2;
else tt=t/2+1;
printf("%d\n",tt);
for(i=1;i<=t/2;i++)
printf("%d %d\n",a[i],a[tt+i]);
if(t%2==1) printf("%d %d",z,a[tt]);AC代码
#include<bits/stdc++.h>
using namespace std;
int n,t,a[200010];
vector v[200010];
void dfs(int x,int y)
{
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=y) dfs(v[x][i],x);
if(v[x].size()==1) t++,a[t]=x;
}
int main()
{
int i,x,y,z,tt;
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
if(n==1) printf("0\n");
else if(n==2) printf("1\n1 2");
else
{
for(i=1;i<=n;i++)
if(v[i].size()>1)
{
dfs(i,i);z=i;
break;
}
if(t%2==0) tt=t/2;
else tt=t/2+1;
printf("%d\n",tt);
for(i=1;i<=t/2;i++) printf("%d %d\n",a[i],a[tt+i]);
if(t%2==1) printf("%d %d",z,a[tt]);
}
return 0;
}
京公网安备 11010502036488号