Skip to main content
Original384 words2 min

题解:P1269 信号放大器

Summary

以服务器为根的树,每条边有衰减量,信号以强度 k 从根出发,过一条边减去衰减量,降到 0 及以下就传不下去;在某结点装放大器可把强度还原成 k,求让信号传遍全树的最少放大器数,办不到则输出 No solution。树形 DP:设 f 为让子树全部收到、信号到达该点所需的最小强度,自底向上对每个儿子在直接传送与装放大器之间取优。只要有一条边衰减量不小于 k 就无解。时间复杂度 O(n)。

题意简述​

一棵以服务器(结点 11)为根的树,每条边有衰减量。信号从服务器以强度 kk 出发,过一条边强度减去其衰减量,强度降到 00 及以下就无法再传。在某结点装放大器可把信号还原成 kk。求让信号传遍全树所需的最少放大器数;无法做到则输出 No solution.。

解题思路​

树形 DP。设 fuf_u 为要让子树 uu 全部收到信号、信号到达 uu 处所需的最小强度,叶子 fu=1f_u=1(能被收到即可)。

自底向上,对 uu 的每个儿子 vv(边权 ww)有两种选择:

  1. 不放大 vv:uu 要把强度 fvf_v 送到 vv,自身强度需不小于 fv+wf_v+w,该儿子对 fuf_u 的贡献即 fv+wf_v+w;
  2. 放大 vv:当 fv+w>kf_v+w>k(uu 满强度 kk 也送不到 vv)时只能在 vv 装放大器,vv 被还原成 kk 后自给自足,uu 只需把信号送达 vv,贡献降为 w+1w+1,放大器数加一。

于是 fuf_u 取 11 与各儿子贡献的最大值,按需放大保证 fu≤kf_u\le k。服务器自带强度 kk,从它 DFS 一遍累计放大器数即为答案。

只要有一条边的衰减量不小于 kk,这条边永远跨不过去,直接输出 No solution.。

时间复杂度为 O(n)O(n)。

参考代码​

645 Bcpp
#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;
}