P3959 宝藏 状压dp
之前写了一份此题关于模拟退火的方法,现在来补充一下状压dp的方法。
其实直接在dfs中状压比较好想,而且实现也很简单,但是网上有人说这种方法是错的。。。并不知道哪错了,但是就不写了,找了一个正解。
正解的区别在于状态,(树高是啥意思),每次都是从当前状态的子集转移过来。这里用到了快速枚举子集的操作,很值得写一下。
题干:
题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 nnn 个深埋在地下的宝藏屋, 也给出了这 nnn 个宝藏屋之间可供开发的m mm 条道路和它们的长度。 小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。 小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。 在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。 新开发一条道路的代价是: L×K\mathrm{L} \times \mathrm{K}L×K L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。 请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。
输入输出格式
输入格式: 第一行两个用空格分离的正整数 n,mn,mn,m,代表宝藏屋的个数和道路数。 接下来 mmm 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 −n1-n1−n),和这条道路的长度 vvv。 输出格式: 一个正整数,表示最小的总代价。 输入输出样例
输入样例#: 复制 输出样例#: 复制 输入样例#: 复制 输出样例#: 复制 说明 【样例解释1】 小明选定让赞助商打通了1 号宝藏屋。小明开发了道路 → \to →,挖掘了 号宝 藏。开发了道路 → \to →,挖掘了 号宝藏。还开发了道路 → \to →,挖掘了3 3号宝 藏。工程总代价为:×+×+×= \times + \times + \times = ×+×+×= 【样例解释2】 小明选定让赞助商打通了1 号宝藏屋。小明开发了道路 → \to →,挖掘了 号宝 藏。开发了道路 → \to →,挖掘了 号宝藏。还开发了道路 → \to →,挖掘了4 4号宝 藏。工程总代价为:×+×+×= \times + \times + \times = ×+×+×= 【数据规模与约定】 对于20% \%%的数据: 保证输入是一棵树,≤n≤ \le n \le ≤n≤,v≤5000v \le 5000v≤ 且所有的 vv v都相等。 对于 %\%%的数据: ≤n≤ \le n \le ≤n≤,≤m≤ \le m \le ≤m≤,v≤5000v \le 5000v≤ 且所有的v v v都相等。 对于70% \%%的数据: ≤n≤ \le n \le ≤n≤,≤m≤ \le m \le ≤m≤,v≤5000v \le 5000v≤ 对于100% \%%的数据: ≤n≤ \le n \le ≤n≤,≤m≤ \le m \le ≤m≤,v≤500000v \le 500000v≤
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
const int maxn = ;
const int maxm = ;
const int maxt = << maxn;
int n,m,a,b,c,ans=INF;
int frog[maxt][maxn],gorf[maxt],dis[maxn][maxn];
int main()
{
read(n);
read(m);
memset(dis,0x3f,sizeof(dis));
duke(i,,m)
{
int x,y,z;
read(x);read(y);read(z);
x--;y--;
dis[x][y] = dis[y][x] = min(dis[x][y],z);
}
memset(frog,0x3f,sizeof(frog));
duke(i,,( << n) - )
{
duke(j,,n - )
{
if((( << j) | i ) == i)
{
dis[j][j] = ;
duke(k,,n - )
{
if(dis[j][k] != INF)
{
gorf[i] |= ( << k);
}
}
}
}
}
duke(i,,n - )
frog[ << i][] = ;
duke(i,,( << n) - )
{
for(int s0 = i - ; s0; s0 = (s0 - ) & i)
{
if((gorf[s0] | i) == gorf[s0])
{
int sum = ;
int ss = s0 ^ i;
duke(k,,n - )
{
if(( << k) & ss)
{
int temp = INF;
duke(h,,n - )
{
if(( << h) & s0)
temp = min(temp,dis[h][k]);
}
sum += temp;
}
}
duke(j,,n - )
if(frog[s0][j - ] != INF)
{
frog[i][j] = min(frog[i][j],frog[s0][j - ] + sum * j);
}
}
}
}
int ans = INF;
duke(i,,n - )
{
ans = min(ans,frog[( << n) - ][i]);
}
printf("%d\n",ans);
return ;
}
P3959 宝藏 状压dp的更多相关文章
- [Luogu P3959] 宝藏 (状压DP+枚举子集)
题面 传送门:https://www.luogu.org/problemnew/show/P3959 Solution 这道题的是一道很巧妙的状压DP题. 首先,看到数据范围,应该状压DP没错了. 根 ...
- LOJ P3959 宝藏 状压dp noip
https://www.luogu.org/problemnew/show/P3959 考场上我怎么想不出来这么写的,状压白学了. 直接按层次存因为如果某个点在前面存过了则肯定结果更优所以不用在意各点 ...
- 【题解】P3959 宝藏 - 状压dp / dfs剪枝
P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的m 条道路和它们的长度. 小明决心亲自前往挖掘所有宝 ...
- 洛谷$P3959\ [NOIp2017]$ 宝藏 状压$dp$
正解:状压$dp$ 解题报告: 传送门$QwQ$ $8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$ 发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j} ...
- [NOIP2017]宝藏 状压DP
[NOIP2017]宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度. 小明决心亲自前往挖 ...
- NOIp2017D2T2(luogu3959) 宝藏 (状压dp)
时隔多年终于把这道题锅过了 数据范围显然用搜索剪枝状压dp. 可以记还有哪些点没到(或者已到了哪些点).我们最深已到的是哪些点.这些点的深度是多少,然后一层一层地往下推. 但其实是没必要记最深的那一层 ...
- 计蒜客 宝藏 (状压DP)
链接 : Here! 思路 : 状压DP. 开始想直接爆搜, T掉了, 然后就采用了状压DP的方法来做. 定义$f[S]$为集合$S$的最小代价, $dis[i]$则记录第$i$个点的"深度 ...
- loj2318 「NOIP2017」宝藏[状压DP]
附带其他做法参考:随机化(模拟退火.爬山等等等)配合搜索剪枝食用. 首先题意相当于在图上找一颗生成树并确定根,使得每个点与父亲的连边的权乘以各自深度的总和最小.即$\sum\limits_{i}dep ...
- Luogu 3959 [NOIP2017] 宝藏- 状压dp
题解 真的想不到这题状压的做法...听说还有跑的飞快的模拟退火,要是现场做绝对滚粗QAQ. 不考虑深度,先预处理出 $pt_{i, S}$ 表示让一个不属于 集合 $S$ 的 点$i$ 与点集 $S$ ...
随机推荐
- 梦想CAD控件COM接口标注样式
增加标注样式 用户可以增加标注样式到数据库,具体实现c#代码如下: private void CreateDim() { //返回控件的数据库对象 MxDrawDatabase database = ...
- Vue组件传值方法调用
1.子组件改变父组件的值 <father label="云盘快照" name="name2"> <son :props='rows' @ ...
- Python3.0科学计算学习之类
类: Python中的类是一个抽象的概念,甚至比函数还要抽象.可以把它简单的看作是数据以及由存取.操作这些数据的方法所组成的一个集合.类是Python的核心概念,是面向对象编程的基础. 类有如下的优点 ...
- LINUX-字符设置和文件格式转换
dos2unix filedos.txt fileunix.txt 将一个文本文件的格式从MSDOS转换成UNIX unix2dos fileunix.txt filedos.txt 将一个文本文件的 ...
- Vue2.0 Props双向绑定报错简易处理办法
在写项目的时候遇到了一个报错问题,虽然功能是正常运行,chrome的提示是:[Vue warn]: Avoid mutating a prop directly since the value wil ...
- Leetcode 133.克隆图
克隆图 克隆一张无向图,图中的每个节点包含一个 label (标签)和一个 neighbors (邻接点)列表 . OJ的无向图序列化: 节点被唯一标记. 我们用 # 作为每个节点的分隔符,用 , 作 ...
- POJ 2356 && POJ 3370 鸽巢原理
POJ 2356: 题目大意: 给定n个数,希望在这n个数中找到一些数的和是n的倍数,输出任意一种数的序列,找不到则输出0 这里首先要确定这道题的解是必然存在的 利用一个 sum[i]保存前 i 个数 ...
- POJ 1026 置换群的k次幂问题
题目大意: 给定了一组对应关系,经过k次幂后,得到新的对应关系b[i],然后将给定的字符串上的第i位字符放置到b[i]的位置上, 如果字符串长度不足n就用空格补足,这里的是空格,也就是str[i] = ...
- [luoguP2890] [USACO07OPEN]便宜的回文Cheapest Palindrome(DP)
传送门 f[i][j] 表示区间 i 到 j 变为回文串所需最小费用 1.s[i] == s[j] f[i][j] = f[i + 1][j - 1] 2.s[i] != s[j] f[i][j] = ...
- Uva10562
Professor Homer has been reported missing. We suspect that his recent research works might have had ...