题意:
给你一颗有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;
}

京公网安备 11010502036488号