gym102222 G. Factories

地址

题目大意:

给一棵n个点的树,选m个点,这m个点只能在叶子节点上,问着m个点中两两之间到达其余各点的距离和最小值是多少
题解:
任意两点的树上距离和问题应从边的贡献角度考虑。

树形dp
设 f[u][i] 表示以 u 为根的子树中,选了 i 个叶子节点的最优解,状态转移方程为:

f[u][i+j]=min(f[u][i+j],f[u][i]+f[v][j]+w∗j∗(j−m))

其中所加项为子节点和父节点之间的边的贡献

/*
[HAOI2015]树上染色 的弱化版
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,n,m,cas;
int main(){
for(scanf("%d",&T);T--;){
scanf("%d%d",&n,&m);
vector<vector<pair<int,ll> > >e(n+);
for(int i=,x,y,z;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
e[x].emplace_back(y,z);
e[y].emplace_back(x,z);
}
if(m==){printf("Case #%d: 0\n",++cas);continue;}
if(n==){printf("Case #%d: %lld\n",++cas,e[][].second);continue;}
vector<vector<ll> > f(n+,vector<ll>(m+,1e14));vector<int>siz(n+,);
function<void(int,int)>dfs=[&](int u,int fa)->void{
bool leaf=;
f[u][]=;
for(auto t:e[u]){
int v=t.first;ll w=t.second;
if(v==fa) continue;
leaf=;
dfs(v,u);
for(int i=min(siz[u],m);~i;i--){
for(int j=min(siz[v],m-i);~j;j--){
f[u][i+j]=min(f[u][i+j],f[u][i]+f[v][j]+w*(m-j)*j);
}
}
siz[u]+=siz[v];
}
if(leaf){f[u][]=;siz[u]=;}
};
int rt=;
for(int i=;i<=n;i++) if(e[i].size()>){rt=i;break;}
dfs(rt,);
printf("Case #%d: %lld\n",++cas,f[rt][m]);
}
return ;
}

第二版

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
const int M=N<<;
const int Kn=;
typedef long long ll;
int T,n,k,cas;
int tot,to[M],nxt[M],head[N],ind[N],siz[N];ll val[M];bool vis[N];
ll f[N][Kn];
inline void add(int x,int y,ll z){
ind[x]++;to[++tot]=y;val[tot]=z;nxt[tot]=head[x];head[x]=tot;
}
void dfs(int u,int fa){
for(int l=head[u];l;l=nxt[l]){
int v=to[l];ll w=val[l];
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
for(int i=min(siz[u],k);i;i--){
for(int j=,re=min(siz[v],i);j<=re;j++){
f[u][i]=min(f[u][i],f[u][i-j]+f[v][j]+w*(k-j)*j);
}
}
}
};
void init_dp(){
for(int i=;i<=n;i++){
f[i][]=;
for(int j=;j<=k;j++) f[i][j]=1e17;
if(ind[i]==) siz[i]=,f[i][]=;
}
}
inline void Clear(){
tot=;
memset(ind,,sizeof ind);
memset(siz,,sizeof siz);
memset(head,,sizeof head);
}
int main(){
for(scanf("%d",&T);T--;Clear()){
scanf("%d%d",&n,&k);
for(int i=,x,y,z;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
int rt=;
for(int i=;i<=n;i++) if(ind[i]>){rt=i;break;}
init_dp();
dfs(rt,);
printf("Case #%d: %lld\n",++cas,f[rt][k]);
}
return ;
}

最新文章

  1. 3.开发Java消息驱动bean实例代码
  2. 利用Javascript判断操作系统的类型实现不同操作系统下的兼容性
  3. Ubuntu中配置Thunderbird登录qq邮箱
  4. flash开发几个问题
  5. WebForm 简单控件、复合控件
  6. android设置图片自适应控件大小
  7. Flv 视频格式(转)
  8. java中四种操作(dom、sax、jdom、dom4j)xml方式详解与比较
  9. Windows环境下使用cygwin ndk_r9c编译x264
  10. [LeetCode]Swap Nodes in Pairs 成对交换
  11. 过河(DP)
  12. 【LuaJIT版】从零开始在 macOS 上配置 Lua 开发环境
  13. HTTP的请求方法OPTIONS
  14. BZOJ 1923: [Sdoi2010]外星千足虫 [高斯消元XOR]
  15. 在Node.js使用Promise的方式操作Mysql
  16. winform中的dateTimePicker控件设置默认值为空
  17. Bitmap的秘密
  18. python shell的交互模式和文本编辑模式
  19. asp.net mvc Htmlhelper简单扩展
  20. 修改IP和DNS的dos命令

热门文章

  1. (原创)C#监控软件通信模型
  2. MySQL5.6.17 绿色版 安装配置
  3. Visual C++ 2010 SP1 x86&amp;x64
  4. Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1
  5. python爬虫之Scrapy学习
  6. MTSC2019-深圳站 议题征集
  7. redis设计与实现(一)简单动态字符串
  8. [摘抄] 2. module对象
  9. AMD规范中模块id的命名规则
  10. [linux]查找最大的文件