题目描述
给定一棵树。要求往树中加入一些边使得从1到其他节点的距离至多是2 。 输出加入边的最小数量。(边全部都是无向的)
题解:好多人都说是贪心,但是我写的是树形dp。
(这道题实在太像小胖守皇宫了)
先贪一步,每条边都由1连出,另一端距离为1。因此可以更新其父亲和儿子。
dp[ u ][ 0 / 1 / 2]:u点由自己/儿子/父亲更新。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 200050 int n,hed[N],cnt; struct EG { int to,nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int dp[N][3]; void dfs(int u,int fa) { dp[u][0]=1; int mn = 0x3f3f3f3f,y=1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa)continue; y=0; dfs(to,u); dp[u][0]+=min(dp[to][0],min(dp[to][1],dp[to][2])); dp[u][2]+=min(dp[to][0],dp[to][1]); dp[u][1]+=min(dp[to][0],dp[to][1]); if(mn>dp[to][0]-dp[to][1])mn=dp[to][0]-dp[to][1]; } if(mn>0)dp[u][1]+=mn; if(y)dp[u][1]=0x3f3f3f3f; } int main() { scanf("%d",&n); for(int f,t,i=1;i<n;i++) { scanf("%d%d",&f,&t); ae(f,t),ae(t,f); } dfs(1,0); int ans = 0; for(int j=hed[1];j;j=e[j].nxt) { int to = e[j].to; ans+=dp[to][0]-1; } printf("%d ",ans); return 0; }