就是給你一棵樹,從1號根開始放無數個機器人,要機器人覆蓋所有邊的最小路徑和;
可以樹形DP但是沒必要,假設只有一個機器人的時候,答案就是 邊數*2 - 根離最遠的葉子的距離,兩個機器人的時候就相當於把走過兩次的邊改成一次,犧牲一些邊獲取一些邊,算貢獻的方法;
具體可以看代碼
#include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; typedef long long ll; const int maxn = 1e6+11; vector<int>G[maxn]; void add(int x,int y){ G[x].push_back(y); } ll ans =0 ; ll dp[maxn]; ll dep[maxn]; int dfs(int x,int fa,int d){ dep[x] = d; for(int i=0;i<G[x].size();i++){ int p = G[x][i]; if(p == fa) continue; dfs(p,x,d+1); dp[x] = max(dp[x],dp[p]+1); } return 0; } bool bml(int a,int b){ return dp[a] > dp[b]; } int dfs2(int x,int fa,int flag){ //flag==1不能計算 sort(G[x].begin(),G[x].end(),bml); if(flag == 0){ ans += min(dep[x] - dp[x] - 2,0LL); } int f = 0; for(int i=0;i<G[x].size();i++){ int p = G[x][i]; if(p == fa) continue; f++; if(f == 1){ dfs2(p,x,1); } else{ dfs2(p,x,0); } } return 0; } int main(){ int t; int aa = 0; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); for(int i=0;i<=n;i++){ dep[i] = 0; dp[i] = 0; G[i].clear(); } for(int i=2;i<=n;i++){ int x; scanf("%d",&x); add(x,i); add(i,x); } dfs(1,0,0); ans = (n-1)*2 - dp[1]; dfs2(1,0,1); printf("Case #%d: %lld\n",++aa,ans); } return 0; }