Main idea of the title:
Here you are
N
N
N-node tree, each edge of the tree has edge weight, which is the traversal time. You can traverse from any node
N
−
k
N-k
N − k points and return to the starting point. What is the shortest time?
k
∈
[
0
,
m
i
n
(
N
,
20
)
]
,
N
∈
[
1
,
1
e
4
]
k\in[0,min(N,20)],N\in[1,1e4]
k∈[0,min(N,20)],N∈[1,1e4]
Problem solving ideas:
Misunderstanding: at the beginning, I thought I wanted to change the root for this arbitrary node, but the relationship between son and father is hard to find!!, And the equation of state I define is d p [ i ] [ j ] dp[i][j] dp[i][j] from i i i this subtree is not selected j j Minimum time spent on j points. This cannot be updated: because it must be connected, my equation only indicates that it is not selected j j j points cannot guarantee connectivity!!!
In fact, it doesn't matter to start from any point: suppose we fix one
1
1
Point 1 is the root, then the answer must be a connected block. In the connected block, you can get the same answer from any point, so we can assume the result from the node with the smallest depth in the connected block!!
So in order to get the connected block: We d p [ i ] [ j ] dp[i][j] dp[i][j] we need to add a limit: Yes i i i this subtree is not selected j j j points, and i i i this point must be selected!! Plus the previous restrictions, and i i Point i must be the point with the lowest depth in the connected block!!
So we d p dp dp is easy to transfer: if there are multiple subtrees, we can enumerate them in two subtrees and choose no number!!
When updating the answer, we need to use the global
a
n
s
ans
ans to update:
Suppose we arrive now
u
u
Point u, then we default to
u
u
Points outside the u subtree are not selected
if(n-siz[u]<=k) ans = min(ans,dp[u][k-(n-siz[u])]);
AC code
#include <bits/stdc++.h> #define mid ((l + r) >> 1) #define Lson rt << 1, l , mid #define Rson rt << 1|1, mid + 1, r #define ms(a,al) memset(a,al,sizeof(a)) #define log2(a) log(a)/log(2) #define lowbit(x) ((-x) & x) #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0) #define INF 0x3f3f3f3f #define LLF 0x3f3f3f3f3f3f3f3f #define f first #define s second #define endl '\n' using namespace std; const int N = 2e6 + 10, mod = 1e9 + 9; const int maxn = 500010; const long double eps = 1e-5; const int EPS = 500 * 500; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; typedef pair<double,double> PDD; template<typename T> void read(T &x) { x = 0;char ch = getchar();ll f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f; } template<typename T, typename... Args> void read(T &first, Args& ... args) { read(first); read(args...); } vector<PII> G[maxn]; int n,k; ll dp[maxn][25], ans; // dp[i][j] means the minimum cost of selecting I from the subtree I and not selecting j points int siz[maxn]; inline void dfs(int u, int fa) { bool tag = 0; siz[u] = 1; for(auto it : G[u]) { if(it.first == fa) continue; dfs(it.first,u); siz[u] += siz[it.first]; if(!tag) { // Determine how many subtrees there are for(int i = 0; i <= min(k,siz[it.first]); ++ i) dp[u][i] = dp[it.first][i] + it.second; if(siz[it.first] <= k) dp[u][siz[it.first]] = 0; tag = 1; } else { ll res[25]; for(int i = 0; i <= k; ++ i) res[i] = LLF; for(int j = 0; j <= k; ++ j) // How many do you take for enumeration? for(int i = 0; i <= j; ++ i) { if(siz[it.first] <= j - i) res[j] = min(res[j],dp[u][i]); else res[j] = min(res[j],dp[u][i]+dp[it.first][j-i]+it.second); } for(int i = 0; i <= k; ++ i) dp[u][i] = res[i]; } } if(n-siz[u]<=k) ans = min(ans,dp[u][k-(n-siz[u])]); if(G[u].size() == 1 && u != 1) dp[u][0] = 0; // This is the only legal answer for leaf node update } int main() { IOS; int _; cin >> _; while(_--) { ans = LLF; cin >> n >> k; for(int i = 0; i <= n+1; ++ i) G[i].clear(); for(int i = 1; i < n; ++ i) { int u, v, w; cin >> u >> v >> w; u ++, v ++; // Set the number to [1,n] G[u].push_back({v,w}); G[v].push_back({u,w}); } for(int i = 0; i <= n; ++ i) for(int j = 0; j <= 20; ++ j) dp[i][j] = LLF; dfs(1,0); cout << ans * 2ll << "\n"; } } /* 3 2 0 0 1 3000 4 1 0 1 81 1 2 41 2 3 59 9 2 0 1 1000 1 2 1200 0 3 1000 3 4 1200 0 5 1000 5 6 1200 0 7 1800 7 8 600 */