附带其他做法参考:随机化(模拟退火、爬山等等等)配合搜索剪枝食用。


首先题意相当于在图上找一颗生成树并确定根,使得每个点与父亲的连边的权乘以各自深度的总和最小。即$\sum\limits_{i}depth_i\times value_{i→fa}$。

看数据范围想状压,固定好一个点为根,然后每个点选没选看做状态$0/1$压位,于是朴素思想是$f[S][S_0][d]$表示已经选了$S$,当前$d$层选了$S'$($S'\subset S$),这样一定可以保证由$S'$导出第$d+1$层,更新答案,而$S$内部其他$x\not\in S'$则不影响更新答案。但是,这样做时间和空间双炸,原因在于$S'$的枚举耗费大量时间。真的有枚举的必要吗?如果把状态设计为$f[S][d]$可以否?如果这样,每次从与$S$联通的剩余点里选子集来更新$f[S|T][d+1]$,选的这些点与已选的连通块中的点的最短边可以预处理出来,如果这种最短边恰好连到了第$d$层,那就是合法的。那么直接$mincost(S,T)*(d+1)$代价更新即可。但是如果真正连到的是非第$d$层的话,这样答案会被多算。不过,这样算出的比实际答案劣,一定存在另一种方案,在之前就已经把这个点选上,从而得出更优解,也就是说这个劣解不会影响答案,最优解总是会被枚举出来并且来更新的,这么做相当于把劣解和最优解全部枚举一遍,$min$一定被最优解更新掉了。所以这个$S'$维度可省。只要枚举$S$,在枚举剩余点子集$T$并计算代价,更新即可。

由于每个点都可以作为起始的根,于是$f[2^i][0]$都初始化为$0$。不过本人后来有点不清楚的是为什么不会撞到一起?比如不同根相同$S$和$d$的怎么处理?发现不影响,这样的话会取一个最优的,剩余点集显然与最优的相连才保证代价可能继续最优。具体的话感觉还是要感性理解。

总结:简化维度时要利用性质,推出某些性质来简化,不是凭空去掉的

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define dbg(x) cerr << #x << " = " << x <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int INF=0x3f3f3f3f;
int dis[<<][],arr[<<];
int f[<<][];
int a[][];
int n,m,ans=INF;
int s[],t[];
inline void preprocess(){
for(register int i=;i<(<<n)-;++i){
s[]=t[]=;
for(register int j=;j<=n;++j)
if(i&(<<j-))s[++s[]]=j;
else t[++t[]]=j;
for(register int j=;j<=t[];++j)
for(register int k=;k<=s[];++k)
MIN(dis[i][t[j]],a[t[j]][s[k]]);
for(register int j=;j<=t[];++j)if(dis[i][t[j]]<INF)arr[i]|=<<t[j]-;
}
}
inline void dp(){
for(register int i=;i<=n;++i)f[<<i-][]=;
for(register int d=;d<n;++d)
for(register int S=;S<(<<n)-;++S)if(f[S][d]<INF)
for(register int j=arr[S];j;j=(j-)&arr[S]){
int res=;
for(register int k=;k<=n;++k)if((<<k-)&j)res+=dis[S][k];
MIN(f[S|j][d+],f[S][d]+res*(d+));
}
} int main(){//freopen("treasure.in","r",stdin);//freopen("treasure.out","w",stdout);
read(n),read(m);memset(f,0x3f,sizeof f),memset(dis,0x3f,sizeof dis),memset(a,0x3f,sizeof a);
for(register int i=,x,y,z;i<=m;++i)read(x),read(y),read(z),MIN(a[x][y],z),a[y][x]=a[x][y];
preprocess();
dp();
for(register int i=;i<n;++i)MIN(ans,f[(<<n)-][i]);
printf("%d\n",ans);
return ;
}

预处理后枚举$S$并枚举$T$,$T$可以近似看做补集,则这个过程可以看做子集枚举,每次在统计一下子集的$cost$,则复杂度$O(n3^n)$。但是好像被平方的吊打了。。。

loj2318 「NOIP2017」宝藏[状压DP]的更多相关文章

  1. BZOJ2073 「POI2004」PRZ 状压DP

    问题描述 BZOJ2073 题解 发现 \(n \le 16\) ,显然想到状压 设 \(opt[S]\) 代表过河集合为 \(S\) 时,最小时间. 枚举 \(S\) 的子集,进行转移 枚举子集的方 ...

  2. 【NOIP2017】 宝藏 状压dp

    为啥我去年这么菜啊..... 我现在想了$20min$后打了$10min$就过了$qwq$. 我们用$f[i][j]$表示当前深度为$i$,访问了状态$j$中的所有点的最小代价. 显然$f[i][j] ...

  3. 「NOIP2017」宝藏

    「NOIP2017」宝藏 题解 博客阅读效果更佳 又到了一年一度NOIPCSP-S 赛前复习做真题的时间 于是就遇上了这道题 首先观察数据范围 \(1 \le n \le 12\) ,那么极大可能性是 ...

  4. [NOIP2017]宝藏 状压DP

    [NOIP2017]宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度. 小明决心亲自前往挖 ...

  5. 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)

    洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...

  6. 洛谷$P3959\ [NOIp2017]$ 宝藏 状压$dp$

    正解:状压$dp$ 解题报告: 传送门$QwQ$ $8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$ 发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j} ...

  7. P3959 宝藏 状压dp

    之前写了一份此题关于模拟退火的方法,现在来补充一下状压dp的方法. 其实直接在dfs中状压比较好想,而且实现也很简单,但是网上有人说这种方法是错的...并不知道哪错了,但是就不写了,找了一个正解. 正 ...

  8. [Luogu P3959] 宝藏 (状压DP+枚举子集)

    题面 传送门:https://www.luogu.org/problemnew/show/P3959 Solution 这道题的是一道很巧妙的状压DP题. 首先,看到数据范围,应该状压DP没错了. 根 ...

  9. NOIp2017D2T2(luogu3959) 宝藏 (状压dp)

    时隔多年终于把这道题锅过了 数据范围显然用搜索剪枝状压dp. 可以记还有哪些点没到(或者已到了哪些点).我们最深已到的是哪些点.这些点的深度是多少,然后一层一层地往下推. 但其实是没必要记最深的那一层 ...

随机推荐

  1. vs code 设置 保存自动格式化vue代码

    配置 ESLint (需安装 Prettier - Code formatter 插件) command + shift + p  打开用户设置 // vscode默认启用了根据文件类型自动设置tab ...

  2. Django路由系统-分组命名匹配

    Django路由系统 分组命名匹配 ​ 在上述基本配置示例中,使用了简单的正则表达式分组匹配来捕获URL中的值并以位置参数的形式传递给视图,例如url(r'^articles/([0-9]{4})/( ...

  3. 统计学习方法 | 第1章 统计学习方法概论 | np.random.rand()函数

    np.random.rand()函数 语法: np.random.rand(d0,d1,d2……dn) 注:使用方法与np.random.randn()函数相同 作用: 通过本函数可以返回一个或一组服 ...

  4. ip速度检测与云主机|VPS的抉择:bandwagonhost digitalocean hostWind Vultr Linode

    最近的梯子断了,网站又被注销了.又到了挑vps的时间了.其实, 这些东西,烦死人了.挺浪费生命的. 首先速度测试, MTR测试 网站速度测试 17CE. http://tool.chinaz.com/ ...

  5. java.io.IOException 断开的管道 解决方法 ClientAbortException: java.io.IOException: Broken pipe

    今天公司技术支持的童鞋报告一个客户的服务不工作了,紧急求助,于是远程登陆上服务器排查问题. 查看采集数据的tomcat日志,习惯性的先翻到日志的最后去查看有没有异常的打印,果然发现了好几种异常信息,但 ...

  6. 其他子配置文件:local.conf

    server         {                 listen 80;                 server_name aa.bb.com;                 i ...

  7. # IDEA相关知识

    目录 IDEA相关知识 安装目录下: 配置目录下: 工程目录下: 名词解释 IDEA相关知识 安装目录下: bin:启动文件,配置信息,IDEA的一些属性信息 jre64:IDEA自带的运行环境 li ...

  8. 2019中山纪念中学夏令营-Day20[JZOJ] T1旅游详解

    2019中山纪念中学夏令营-Day20[JZOJ] 提高组B组 Team_B组 T1 旅游 Time Limits: 2000 ms  Memory Limits: 262144 KB Descrip ...

  9. 关于VUE 配置文件config详解内容

    // const path = require('path'); module.exports = { /** 区分打包环境与开发环境 * process.env.NODE_ENV==='produc ...

  10. MySQL数据库增删改查SQL语句(2018整理集合大全)

    查看数据库 show databases;  使用数据库 use 数据库名; 创建数据库 CREATE DATABASE 数据库名; 删除数据库 DROP DATABASE 数据库名; 创建表 cre ...