分析
居然还要看按照深度进行操作,大意了,没有学
其实就是一个贪心。因为如果这个点距离根节点超过2,只需要考虑边加在哪里。有三个选择:父节点,自己,子节点。选择父节点更优。记录两个数组:
vis[i]:此节点是否与根节点直接相连 op[i]:此节点与根节点的距离是否大于2
每次从深度最大的一个节点里选出一个,如果他与根节点的距离大于2并且他的父节点
并没有与根节点直接相连。那么就加一条
的边,同时更新
周围节点的
标记。还有一些预处理细节。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=2e5+10;
int n,tot,ans;
int h[N],nex[N<<1],ver[N<<1],dep[N],fa[N];
bool vis[N],op[N];
struct nk
{
    int x;
    bool operator < (const nk &b)const
    {
        return dep[x]<dep[b.x];//深度从大到小 
    }
    nk(int xx):x(xx){}
};priority_queue<nk>q;
inline void add(int x,int y)
{
    nex[tot]=h[x];
    ver[tot]=y;
    h[x]=tot++;
}
inline void dfs(int u,int v)
{
    dep[u]=dep[v]+1;fa[u]=v;
    for (int i=h[u];~i;i=nex[i])
    {
        int j=ver[i];
        if(j==v) continue;
        dfs(j,u);
    }
}
int main()
{
    memset(h,-1,sizeof(h));
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    vis[1]=1;//相连
    for (int i=h[1];~i;i=nex[i]) vis[ver[i]]=1;
    dfs(1,0);
    for (int i=1;i<=n;i++) q.push(i);
    while(!q.empty())
    {
        nk u=q.top();q.pop();
        int x=u.x;
        if(!op[x])
        {
            if(vis[x]||vis[fa[x]]) continue;
            ans++;vis[fa[x]]=1;
            for (int i=h[fa[x]];~i;i=nex[i]) op[ver[i]]=1;
        }
    }
    printf("%d\n",ans);
    return 0;
}
京公网安备 11010502036488号