2020牛客国庆集训派对day1 C. Bob in Wonderland
题意:
一棵树,问最少移动多少次边可以使其变成一个链?
移动是指:从原位置拆下并连到新位置,这样算一次
题解:
错误思路
我一开始在想既然求最少移动次数,那我们就尽可能在原本的就存在的链的基础上进行修改,也就是先找树中最长的链(即树的直径),然后看这条链上有多少子链相连,拆下来再连上即可,所以先跑两边dfs,求出最长直径,并记录直径上的点,然后依次查看直径上的点的度数是否大于2,如果大于2就说明除了前后两个点,还有其他点相连,注意如果7连在6上,然后6连在直径上,那6和7是算一个整体的,所以只需要查看直径点的度数即可
正确思路
但是。。代码就是wa。。。感觉是两边dfs不对???
我也很懵逼,后来又想了想,其实完全没这么复杂,因为没有必要先求直径,我们直接求所有点的度数,然后查看度数是否大于等于2,并累加即可
而且,如果链的上面存在链怎么办?也就是7连着6,6连着5,5连着直径上一点,但是6还连接着其他链,这样我们只查看直径上的点就不对了,应该是查看所有度数大于2的点
先求树的直径纯属画蛇添足,因为如果所有点组成链,那么所有点的度数必然小于等于2(两端等于1,中间等于2),所以直接查看所有点度数就行
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+9;
vector<int>G[maxn];
int main()
{
int n;
cin>>n;
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
int sum=0;
for(int i=1;i<=n;i++)
{
int w=G[i].size()-2;
if(w>0)
{
sum+=w;
}
}
cout<<sum<<endl;
return 0;
}