题意简述
一棵以服务器(结点 )为根的树,每条边有衰减量。信号从服务器以强度 出发,过一条边强度减去其衰减量,强度降到 及以下就无法再传。在某结点装放大器可把信号还原成 。求让信号传遍全树所需的最少放大器数;无法做到则输出 No solution.。
解题思路
树形 DP。设 为要让子树 全部收到信号、信号到达 处所需的最小强度,叶子 (能被收到即可)。
自底向上,对 的每个儿子 (边权 )有两种选择:
- 不放大 : 要把强度 送到 ,自身强度需不小于 ,该儿子对 的贡献即 ;
- 放大 :当 ( 满强度 也送不到 )时只能在 装放大器, 被还原成 后自给自足, 只需把信号送达 ,贡献降为 ,放大器数加一。
于是 ,按需放大保证 。服务器自带强度 ,从它 DFS 一遍累计放大器数即为答案。
只要有一条边的衰减量不小于 ,这条边永远跨不过去,直接输出 No solution.。
时间复杂度为 。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=20005;
int k,ans;
int f[N];
bool vis[N];
vector<pair<int,int>> G[N];
void dfs(int u)
{
vis[u]=1;
f[u]=1;
for(auto [v,w]:G[u])
{
if(vis[v])continue;
dfs(v);
if(f[v]+w>k)
{
ans++;
f[u]=max(f[u],w+1);
}
else f[u]=max(f[u],f[v]+w);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
int mx=0;
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
while(t--)
{
int v,w;
cin>>v>>w;
G[i].push_back({v,w});
mx=max(mx,w);
}
}
cin>>k;
if(mx>=k)
{
cout<<"No solution.\n";
return 0;
}
dfs(1);
cout<<ans<<'\n';
return 0;
}