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


首先题意相当于在图上找一颗生成树并确定根,使得每个点与父亲的连边的权乘以各自深度的总和最小。即$\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. 【.NET】由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值。

    前言 上段时间做项目时,遇到如题之类问题,如今过去有一段时间了,具体出现的情形忘了,当时虽然找到了解决方法,但是依旧没有弄明白出现此种情况是何种原因,后来在微软的帮助支持中心找到了答案,特此记录,以防 ...

  2. elasticsearch-head-master下运行npm install报npm WARN elasticsearch-head@0.0.0 license should be a valid SPDX license expression

    2个月没有启动es和es配套服务,今天运行时,发现如下问题: 运行npm install 出现npm WARN elasticsearch-head@0.0.0 license should be a ...

  3. Python知识点面试题

    一. DB类 索引相关: 1. mysql索引种类 2. 什么是覆盖索引? MySQL目前主要有以下几种索引类型:1.普通索引2.唯一索引3.主键索引4.组合索引:遵循最左前缀规则5.全文索引 其他: ...

  4. PhpMyAdmin提示未加密

    新版本的PhpMyAdmin 增强了安全性,需要在配置文件设置一个短语密码.否则进入之后会有“配置文件现在需要一个短语密码.”的红色警叹提示. 解决方法: .将 phpMyAdmin/librarie ...

  5. Oracle 看出表结构与属性、表空间设计

    1.Oracle 查看表空间 SELECT b.comments as 注释, a.column_name as 列名, a.data_type || '(' || a.data_length || ...

  6. 【CUDA开发】__syncthreads的理解

    __syncthreads()是cuda的内建函数,用于块内线程通信. __syncthreads() is you garden variety thread barrier. Any thread ...

  7. 【Python开发】网页爬取心得

    转载:python 爬虫抓取心得分享 title:python 爬虫抓取心得分享 0x1.urllib.quote('要编码的字符串')如果你要在url请求里面放入中文,对相应的中文进行编码的话,可以 ...

  8. Web Service简介与开发实例

    简介 1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的 ...

  9. C# XML操作之一:使用XmlDocument来读写

    所有代码都在同一个类中,含有对象 XmlDocument doc = new XmlDocument(); 新建XML,并且写入内容 private void button4_Click(object ...

  10. Eclipse注释

    首先,Window------>preferences------>java------>Code Style------>Code Templates------>Co ...