Skip to main content
390 words2 min

题解:P1269 信号放大器

题意简述

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

解题思路

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

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

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

于是 fu=max(1,maxv(各儿子贡献))f_u=\max\bigl(1,\max_v(\text{各儿子贡献})\bigr),按需放大保证 fukf_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;
}