题意:
给你一颗有n个节点的无向树,你可以往树中加无向边,求你形成1节点到任意一个节点距离小于等于2的图加边的最小次数?

思路:
你可以认为是求一个变形的最小支配集,即求以1节点为根节点时第0,1,2层无需考虑的最小支配集,所以可以用动态规划和贪心算法解决。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

vector<int> g[300005];
const ll inf=1000000007;
int dp[300005][3], ans=0;

void dfs(int v,int d,int f)
{
    if(f!=-1&&g[v].size()==1)
    {
        if(d<=2)
        {
            dp[v][0]=1;
            dp[v][1]=0;
            dp[v][2]=0;
        }
        else
        {
            dp[v][0]=1;
            dp[v][1]=inf;
            dp[v][2]=0;
        }
        return ;
    }
    dp[v][0]=1;
    dp[v][2]=0;
    int flag=0, mi=inf;
    for(int i=0; i<g[v].size(); i++)
    {
        if(g[v][i]!=f)
        {
            dfs(g[v][i],d+1,v);
            if(d<=2)
            {
                dp[v][0]+=min(min(dp[g[v][i]][0],dp[g[v][i]][1]),dp[g[v][i]][2]);
                dp[v][1]+=min(dp[g[v][i]][0],dp[g[v][i]][1]);
                dp[v][2]+=min(dp[g[v][i]][0],dp[g[v][i]][1]);
                flag=1;
            }
            else
            {
                dp[v][0]+=min(min(dp[g[v][i]][0],dp[g[v][i]][1]),dp[g[v][i]][2]);
                dp[v][1]+=min(dp[g[v][i]][0],dp[g[v][i]][1]);
                dp[v][2]+=min(dp[g[v][i]][0],dp[g[v][i]][1]);
                mi=min(mi,abs(dp[g[v][i]][0]-dp[g[v][i]][1]));
                if(dp[g[v][i]][0]<=dp[g[v][i]][1])
                {
                    flag=1;
                }
            }
        }
    }
    if(flag==0)
    {
        dp[v][1]+=mi;
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0; i<n-1; i++)
    {
        int u, v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0,-1);
    cout << min(dp[1][0],dp[1][1]) << endl;
    return 0;
}