CF70E Information Reform 题解
CF70E Information Reform
树形 DP 好题。一开始想成了换根,想了 2h 发现不太可做,主要是不会设计状态。套路地将节点
观察到
那么状态设计就是本题的难点,首先得到一个极为重要的引理如下。这个引理告诉我们,对于一个节点
引理:设
是离节点 最近的区域信息中心。对于树上两点 ,若 ,则在 路径上的所有点 都满足 。
那么这个问题就简单了,对于每个连通块在其根部计算贡献,设
实际实现中,我们只需要再记录一个使
输出方案也是容易的。
#include<bits/stdc++.h>
using namespace std;
constexpr int MAXN=205;
int n,k,d[MAXN],dis[MAXN][MAXN];
vector<int>G[MAXN];
int f[MAXN][MAXN],g[MAXN],ans[MAXN];
void getdis(){
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
void dfs(int u,int fno){
memset(f[u],0x3f,sizeof(int)*(n+5));
for(int i=1;i<=n;++i) f[u][i]=d[dis[u][i]]+k;
for(auto v:G[u]){
if(v==fno) continue;
dfs(v,u);
for(int i=1;i<=n;++i)
f[u][i]+=min(f[v][i]-k,f[v][g[v]]);
}
for(int i=1;i<=n;++i) if(f[u][i]<f[u][g[u]]) g[u]=i;
}
void dfs2(int u,int fno){
for(auto v:G[u]){
if(v==fno) continue;
if(f[v][ans[u]]-k<f[v][g[v]]) ans[v]=ans[u];
else ans[v]=g[v];
dfs2(v,u);
}
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin>>n>>k;
for(int i=1;i<n;++i) cin>>d[i];
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=n;++i) dis[i][i]=0;
for(int i=1,u,v;i<n;++i){
cin>>u>>v;
G[u].emplace_back(v);
G[v].emplace_back(u);
dis[u][v]=dis[v][u]=1;
}
getdis();
dfs(1,0);
cout<<f[1][g[1]]<<'\n';
ans[1]=g[1];
dfs2(1,0);
for(int i=1;i<=n;++i) cout<<ans[i]<<" \n"[i==n];
return 0;
}
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程 ,由上可知证毕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】