当前位置: 首页 > news >正文

P3959 [NOIP 2017 提高组] 宝藏 题解

link

题目要求任选图中一点为根,通过拓展道路最终形成一棵树,使得代价总和最小,代价受深度和边权两个因素影响。
容易想到一种爆搜,任选一点为根,每次扫描已选点来不断尝试拓展道路,但这样做太蛋疼了,我们尝试优化。

此时一看数据范围 \(n\le12\),考虑把思路往状压 \(dp\)上引导或寻找类似做法,我们发现:

  1. 在最终形成的树中,同一深度的点不受拓展先后顺序的影响,也就是说我们可以尝试一次性拓展同一深度的点。
  2. 对于已连通的点集 \(s\),我们不关心它的具体形态,只需保证其代价最小,因为在后续拓展中的代价与 \(s\) 的形态无关。

这样的条件启发我们可以 “深度” 为阶段,“点集” 为状态尝试设计 \(dp\)

\(dp\) 状态 \(f_{i,s}\) 为当前拓展到深度 \(i\),状态为 \(s\) 的点均连通时的最小代价,转移方程如下:

\[f_{i,s}=\min_{s \in z 且新点均与 z连通} \{f_{i-1,z} +(i-1)\times cost(z,s) \} \]

其中转移条件 \(s\in z\) 意味着新的一层只能打通原来没有的点,这时就需要用到子集枚举的手段,这样做时间复杂度是 \(O(3^n)\) 的。

\(cost(z,s)\) 表示从旧状态到新状态的代价,这个可以通过预处求得。

最终一层枚举起点,一层枚举深度,再加上子集枚举 \(dp\) 总时间复杂度是 \(O(n^2 3^n)\) 的,可以通过本题。

点击查看代码
const int N=15;
const int M=1<<12;
const int inf=0x3f3f3f3f;
int cost[M][M],n,m,e[N][N];
ll f[N][M],ans=inf;
void init(){for(int s=1;s<(1<<n);s++){   //当前层for(int z=s;z;z=(z-1)&s){//上一层为其子集,保证都是新点转移过来if(s==z) continue;for(int i=0,tmp=inf;i<n;i++,tmp=inf){    //枚举新点if(!( ((s^z)>>i) &1)) continue;for(int j=0;j<n;j++) if((z>>j)&1) tmp=min(tmp,e[j][i]); //选择最短边if(tmp>=inf){cost[z][s]=inf;break;}else cost[z][s]+=tmp;    }}}
}
ll DP(int x){memset(f,0x3f,sizeof(f));f[0][1<<x]=0;//初始免费边ll res=inf;for(int i=1;i<n;i++){for(int s=1;s<(1<<n);s++){for(int z=s;z;z=(z-1)&s){if(s==z) continue;f[i][s]=min(f[i][s],f[i-1][z]+1ll*i*cost[z][s]);}if(s==(1<<n)-1) res=min(res,f[i][s]);}}return res;
}
void xpigeon(){rd(n,m);if(n==1){cout<<0<<'\n';return ;}memset(e,0x3f,sizeof(e));for(int i=0;i<n;i++){e[i][i]=0;}for(int i=1,u,v,w;i<=m;i++){rd(u,v,w);u--,v--;e[u][v]=e[v][u]=min(e[u][v],w);}init();for(int i=0;i<n;i++) ans=min(ans,DP(i));cout<<ans<<'\n';
}
signed main() {ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);xpigeon();return 0;
}
http://www.jsqmd.com/news/2267/

相关文章:

  • (二)若依前后端分离版本二次开发 代码生成、目录添加、数据字典维护
  • C#与Access数据库操作简易指南:增删改查及类封装
  • 对之前部署hbase总结
  • 深入解析:分享一个完整的uniapp车牌号输入组件
  • 国产 CAD 新选择!NanoCAD 24.0:全功能 DWG 支持 + 3D 建模优化,多领域设计效率拉满
  • java 框架mybatis_01(
  • 扣子Coze智能体实战:自动采集1000条小红书爆款笔记 ,自动写入飞书多维表格
  • 【CVCVCV】dataloader报错RuntimeError: Caught RuntimeError in DataLoader worker process 0
  • Fluent Bit采集k8s日志
  • 公众号文章添加附件,公众号运营必学加分技巧-支持Word、Excel、PDF等文件
  • python脚本划分数据集
  • 发送一朵云
  • FPExpress 2025.1 使用方法
  • Spring IO工具类及其用法
  • Typora+Cnblog实现Markdown图片自动上传
  • Moka人力资源管理系统入选 NextGen Tech30 榜单
  • 嵌套粒子群优化(Nested PSO)的电力系统经济调度方案
  • 实用指南:C++编程学习(第34天)
  • Java集合 - 教程
  • 用前端(HTML+Node.js)实现物品借用登记:完整代码示例
  • Google智能体Jules小试牛刀
  • 搞笑椅子机房语录
  • 在AI技术快速实现创意的时代,挖掘渗透测试框架新需求成为关键挑战
  • 基于区域的空间域图像融合MATLAB实现
  • Qt - 音视频采集
  • 梳理 | 脑神经科学原理学习资料整理
  • 如何做有效的Bug管理?
  • PCI-SIG的成员
  • .NET 8 内存泄漏分析
  • 2025年9月16日纸质证书 - 高同学PostgreSQL管理员(中级)认证