P1269 信号放大器
给一棵有根树,树的边上有距离。根上有一个信号发射器,会发生强度为 h 的信号,信号会往所有的节点传播,然而每经过
一条边强度就会削减距离的大小,当信号到达某点时小于 1,则信号传递失败。树上每个节点可以放信号放大器。信号经过放大
器后会被重新放大为 h。问至少要放多少个信号才能使每个点的信号都能传输成功,或者判断无解。
$n ≤ 20000$。
来自大佬的原话:树形$DP$显然。
我怎么看不出来呢?还是太蒟了。。。
设$f[u]$为传递整个子树$u$所需的最小信号,$g[u]$表示传递整个子树$u$所需要的最少的信号放大器
若不放放大器,则
$g[u]=sum g[v]$
$f[u]=max(f[u],f[v]+dis[u,v])$
考虑放的情况:当$f[v]+dis[u,v]>h$时必须在$v$放一个信号放大器,则$f[u]=1,g[u]++$
时间复杂度$ O(n)$
%%GEOTCBRL%%
#include<iostream> #include<cstdio> #include<vector> #include<cmath> #include<cstdlib> #define N 1010101 using namespace std; int f[N],g[N],h,n; vector<pair<int,int> >G[N]; bool flg=true; void dfs(int u,int fa){ int siz=G[u].size(),Tim=0,son=0; for(int i=0;i<siz;i++){ int v=G[u][i].first,tim=G[u][i].second; if(v==fa){ Tim=tim; continue; } if(tim>=h) { printf("No solution. "); exit(0); } dfs(v,u); ++son; g[u]+=g[v]; f[u]=max(f[u],f[v]+tim); } if(!son) g[u]=0,f[u]=1; else{ if(u!=1&&f[u]+Tim>h){ f[u]=1; g[u]++; } } } int main() { scanf("%d",&n); for(int v,w,k,i=1;i<=n;i++){ scanf("%d",&k); while(k--){ scanf("%d%d",&v,&w); G[i].push_back(make_pair(v,w)); // G[v].push_back(make_pair(i,w)); } } scanf("%d",&h); dfs(1,0); printf("%d ",g[1]); return 0; }