Luogu P3959 宝藏 题解 [ 紫 ] [ 状压 dp ] [ 二项式定理 ]
宝藏:一个对着蓝书代码调都能调两个小时的大毒瘤,但是思路还是很值得借鉴的,有普通状压和三进制状压两种做法,或者暴搜剪枝也可以(这里不介绍暴搜剪枝做法)。
普通状压做法
观察到 \(n\le 12\),首先想到状压。
但考虑到普通的状压不太行,因为 \(K\) 这个数算在代价里,会导致这个 dp 有后效性。同时也观察到最终形成的方案一定是一棵树。
因此,我们尝试把 \(K\) 加入状态中。
定义 \(dp_{K,i}\) 表示这棵树扩展到第 \(K\) 层,状态为 \(i\) 时的最小花费。
那么我们在转移的时候枚举一下 \(i\) 的子集 \(j\),从 \(dp_{K-1,j}+cost\times(K-1)\) 转移就好了。
所以我们预处理的时候要把每个状态的能转移到该状态的子集列出来。
这个操作,我们可以先列出每个状态拓展所有点的边后的状态 \(expd_i\),并且记录下每个状态 \(i\) 扩展第 \(j\) 个点的最小花费 \(road_{i,j}\),目的是便于计算 \(cost\) 的值。
于是我们枚举每一个状态的子集,判断这个状态是否是该子集的 \(expd\) 的子集。如果是,则可以转移,枚举所有需要扩展的点,加上它的 \(road\) 即可。
细节
枚举某个状态的子集
枚举 \(i\) 这个状态的非零子集,可以通过如下代码实现:
for(int j=i;j!=0;j=((j-1)&i))
如果要枚举 \(0\),必须特判;如果不能枚举自身,那么把 \(j\) 初始化重设一下:int j=((i-1)&i)。
例子:枚举 \(14\) 的非零子集(包括自己)。

因为每次都从某个子集减 \(1\),并且还与了自身,所以保证每次都是子集,且比以前都小,保证了不重、不漏。
位运算
注意优先级,很容易被坑,多打括号。
优先级从大到小:
- * 和 / 乘除
- + 和 - 加减
- >> 和 << 左移右移
- > 和 < 和 == 和 != 和 >= 和 <= 比较符
- ^ (xor) 异或
- | 位或
注意: ! 和 ~ 的优先级很高,不要乱用,甚至高于加减的优先级,尽量加括号使用!!!
时间复杂度分析
二项式定理:
\]
其中,组合数的系数可以看作是杨辉三角里的数,其实这个定理初二就学过。
该定理可以逆用。
那么我们用此来解决本题枚举子集部分的复杂度分析:
\]
这就是 dp 部分复杂度,预处理的复杂度为 \(O(m\times2^n)\)。
总体复杂度 \(O(n\times3^n+m\times2^n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
int n,m,expd[4505];
ll d[15][15],road[4505][15],dp[15][4505],ans=0x3f3f3f3f3f3f3f3f;
vector<pi>frm[4505];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
memset(d,0x3f,sizeof(d));
memset(road,0x3f,sizeof(road));
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
d[u][v]=d[v][u]=min(1ll*w,d[u][v]);
}
for(int i=1;i<=n;i++)d[i][i]=0;
//初始化expand和road函数
for(int i=0;i<(1<<n);i++)
{
expd[i]=i;
for(int j=1;j<=n;j++)
{
if(((i>>(j-1))&1)==0)continue;//位运算不要偷懒,这里写 !(i>>(j-1))&1 是错的!
road[i][j]=0;
for(int k=1;k<=n;k++)
{
if(((i>>(k-1))&1)==1)continue;
if(d[j][k]>=(0x3f3f3f3f/2))continue;
expd[i]=expd[i]|(1<<(k-1));
road[i][k]=min(road[i][k],d[j][k]);
}
}
}
//初始化每个状态的子集们
for(int i=0;i<(1<<n);i++)
{
for(int j=i;j!=0;j=((j-1)&i))
{
if((i&expd[j])!=i)continue;
ll cst=0;
for(int k=1;k<=n;k++)
{
if(((i^j)>>(k-1))&1)cst+=road[j][k];
}
frm[i].push_back({j,cst});
}
}
//状压dp
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<n;i++)dp[1][1<<i]=0;
for(int i=1;i<=n;i++)//层数
{
for(int j=0;j<(1<<n);j++)//当前状态
{
for(auto tmp:frm[j])
{
int st=tmp.first;
ll cst=tmp.second;
dp[i][j]=min(dp[i][j],dp[i-1][st]+cst*(i-1));// i要-1 ,不要读错题
}
}
}
for(int i=1;i<=n;i++)ans=min(ans,dp[i][(1<<n)-1]);
cout<<ans;
return 0;
}
三进制状压做法
口胡一下,有点难写。
三进制数,该位为 \(0\) 代表没有开辟,\(1\) 代表早就开辟,可以转移;\(2\) 表示刚开辟,不能转移。
这种做法依然要记录层数。除此之外还要记录 \(3\) 的次幂之类的东西,常数极大。
注意转移时只要转移最高位的 \(1\),因为其他位的 \(1\) 以后一定会循环到,避免了重复枚举。跟愤怒的小鸟那题挺像的。
复杂度 \(O(n^2\times3^n)\),代码就不放了。
Luogu P3959 宝藏 题解 [ 紫 ] [ 状压 dp ] [ 二项式定理 ]的更多相关文章
- 【NOIP2017】宝藏 题解(状压DP)
题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 nnn 个深埋在地下的宝藏屋, 也给出了这 nnn 个宝藏屋之间可供开发的m mm 条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中 ...
- bzoj 2669 题解(状压dp+搜索+容斥原理)
这题太难了...看了30篇题解才整明白到底咋回事... 核心思想:状压dp+搜索+容斥 首先我们分析一下,对于一个4*7的棋盘,低点的个数至多只有8个(可以数一数) 这样的话,我们可以进行一个状压,把 ...
- noi省选 [九省联考2018]一双木棋题解(状压dp)
比浙江简单多了........ 题目转送:https://www.luogu.org/problemnew/show/P4363 分析: 我们注意到n和m都很小,考虑一下状压dp. 显然,棋子摆成的形 ...
- BZOJ 1087 题解【状压DP】
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3112 Solved: 1816[Submit][ ...
- LibreOJ 6177 题解(状压DP)
题面 传送门 分析 刚看到这道题时想的是跟最短哈密顿路类似的二进制状压DP,先用floyd处理距离 但是此题用二进制不够,应该用三进制 0,1,2分别表示未送,正在送,已送完 dp[s][i]表示当前 ...
- 【FZYZOJ】愚人节礼物 题解(状压DP)
前言:麻麻我会写状压DP了! ---------------------------- 题目描述 愚人节到了!可爱的UOI小朋友要给孩子们送礼物(汗-原题不是可爱的打败图么= =..).在平面直角坐标 ...
- 【SCOI2005】互不侵犯 题解(状压DP)
前言:一道状压DP的入门题(可惜我是个DP蒟蒻QAQ) ------------------ 题意简述:求在一个$n*n$的棋盘中放$k$个国王的方案数.注:当在一个格子中放入国王后,以此格为中心的九 ...
- P1278 单词游戏【题解】(状压dp)
单词游戏 题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍 ...
- 【SCOI2008】奖励关 题解(状压DP+期望)
题目链接 题目大意:给定$n$个宝物,每次随机抛出一个宝物,奖励分数为$p_i$.但如果选这个宝物必须选过它的前置宝物集合.共进行$K$轮问最优策略下的期望. $n\leq 15,-10^6\leq ...
- P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)
题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...
随机推荐
- ELSTICSEARCH 将数据从热节点转到冷节点
在ES查询时,有些数据是热点数据,这些数据是需要需要更好的机器配置的节点,当数据变得不是那么重要的时候,我们需要转到配置相对低的节点上. 比如热点新闻专题,我们需要更好的机器,热点过后,这些数据不再需 ...
- 实用&free的音频格式转化工具
最近写的博客居然是7年前,今天给小朋友下载歌曲时在网上搜了好多格式转化的方法,挨个尝试了之后发现好多是收费的,或者不支持某种格式转化的,但还是大浪淘沙到一些实用的工具.分享给大家参考,同时也督促自己不 ...
- 关于Pro addin中,控制dockpane的状态
在Pro SDK中,可以通过dackpane的Hide()方法,对面板进行隐藏. DockPane pane = FrameworkApplication.DockPaneManager.Find(& ...
- sql 依据时间间隔分组,获取第一条数据
时序数据的数据量比较大,抛去异常点外,变化相对比较有线性规律,业务上需要对结果进行抽取显示. 原始数据时序标签(部分示例) 根据时间字段,计算时间字段和指定时间的时间戳差值,然后除以固定间隔(示例中间 ...
- AE对象序列化
当我们编写AE程序时,通常会遇到需要存储某个AE对象的情况,比如Layer,Element,Map,Legend,NorthArrow等等这些.举个例子说明一下:在我们编辑Featurelayer时, ...
- LeetCode题集-6 - Z 字形变换
题目:将一个给定字符串 s 根据给定的行数 numRows ,以从上往下.从左到右进行 Z 字形排列. 这一题作为中等难度,下面和大家分享几种不同的解法. 01.二维矩阵模拟法 所谓二维矩阵模拟法就是 ...
- OS之《机械硬盘》
数据的组织 一个磁盘设备 ---->多个物理盘片 一个物理盘片---->正反两面存储面 一个存储面---->多个磁道(每个磁道上存储容量时一样的,可存储相同数目的二进制位),所以,内 ...
- GPU 驱动漏洞:窥探驱动漏洞利用的技术奥秘
GPU 驱动漏洞:窥探驱动漏洞利用的技术奥秘 本文尝试以 GPU 漏洞为引介绍围绕 GPU 驱动这一攻击面,安全研究人员对内核漏洞利用技术做的一些探索. 背景介绍 目前移动 SOC 平台上由多个硬件模 ...
- MySQL8设置root用户远程访问
查询当前root状态,默认root的host是localhost use mysql; select user,host from user; update root的host为% update us ...
- 【网站搭建】Docsify+Gittalk的配置过程记录分享。原创!
Gittalk 配置 这个不一定最先配置,我也不建议你最先配置这个,这个最好最后配置. 萌狼蓝天把这个的配置写在第一条,是因为我在这折腾了很久,就是因为网上抄来抄去的答案,除了迷惑萌狼蓝天难以给萌狼蓝 ...