洛谷P3959 宝藏
去年NOIP第二毒瘤(并不)的题终于被我攻克了,接下来就只剩noip难度巅峰列队了。
首先说一下三种做法:随机化,状压DP和搜索。
前两种做法我都A了,搜索实在是毒瘤,写鬼啊。
有些带DFS的记忆化搜索版状压DP,我看着感觉有点问题......
就连随机化里面那个贪心我看起来也感觉是错的.....但还是A了。
所以考试的时候不要虚,大胆写随机化,随便混个几十分,说不定就A了。
20分算法:给定一棵树,枚举根即可。
#include <cstdio>
#include <algorithm> const int N = , M = , INF = 0x7f7f7f7f; int G[N][N], n; int DFS(int x, int k, int f) {
int ans = ;
for(int i = ; i <= n; i++) {
if(G[x][i] && i != f) {
ans += DFS(i, k + , x);
ans += G[x][i] * k;
}
}
return ans;
} int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = , x, y, z; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
if(G[x][y]) {
z = std::min(z, G[x][y]);
}
G[x][y] = G[y][x] = z;
} int ans = INF;
for(int i = ; i <= n; i++) {
ans = std::min(ans, DFS(i, , ));
}
printf("%d", ans); return ;
}
20分代码
40分算法:边权相等,据说可以BFS/DFS/prim,反正我搞不出来....
70分算法:直接枚举全排列,然后按照排列顺序依次加点,贪心即可。
这里有个问题:当前点的深度会对后面节点造成影响,所以贪心出来的不一定是这个顺序的最优解。
但是你有很多排列啊,说不定哪一次就搞出正解来了呢?
#include <cstdio>
#include <algorithm> const int N = , M = , INF = 0x7f7f7f7f; int G[N][N], n, a[N], dis[N]; int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = , x, y, z; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
if(G[x][y]) {
z = std::min(z, G[x][y]);
}
G[x][y] = G[y][x] = z;
} for(int i = ; i <= n; i++) {
a[i] = i;
}
int ans = INF;
do {
dis[a[]] = ;
int t_ans = ;
for(int i = ; i <= n; i++) {
bool f = ;
int small = INF, pos;
for(int j = ; j < i; j++) {
if(!G[a[i]][a[j]]) {
continue;
}
f = ;
if(small > dis[a[j]] * G[a[i]][a[j]]) {
small = dis[a[j]] * G[a[i]][a[j]];
pos = j;
}
}
if(!f) {
t_ans = INF;
goto flag;
}
t_ans += small;
dis[a[i]] = dis[a[pos]] + ;
}
flag:
ans = std::min(ans, t_ans);
}while(std::next_permutation(a + , a + n + )); printf("%d", ans);
return ;
}
AC代码
100分算法_随机化:
把70分算法改进一下,不枚举全排列,而是random_shuffle,说不定哪次就搞出正解来了呢?
然后就真A了......考场上还不是送分送到死啊,反向筛人。跑的还贼快...
#include <cstdio>
#include <algorithm> const int N = , M = , INF = 0x7f7f7f7f; int G[N][N], n, a[N], dis[N]; int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = , x, y, z; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
if(G[x][y]) {
z = std::min(z, G[x][y]);
}
G[x][y] = G[y][x] = z;
} for(int i = ; i <= n; i++) {
a[i] = i;
}
int ans = INF, T = ;
while(T--) {
std::random_shuffle(a + , a + n + );
dis[a[]] = ;
int t_ans = ;
for(int i = ; i <= n; i++) {
bool f = ;
int small = INF, pos;
for(int j = ; j < i; j++) {
if(!G[a[i]][a[j]]) {
continue;
}
f = ;
if(small > dis[a[j]] * G[a[i]][a[j]]) {
small = dis[a[j]] * G[a[i]][a[j]];
pos = j;
}
}
if(!f) {
t_ans = INF;
goto flag;
}
t_ans += small;
dis[a[i]] = dis[a[pos]] + ;
}
flag:
ans = std::min(ans, t_ans);
} printf("%d", ans);
return ;
}
AC代码
100分算法_状压DP:
好,这个才是这篇博客的主要目的。
我们发现这个深度很难搞啊...
然后又发现同一个深度的话,边权的加权是一定的。
然后我们考虑把边权搞到状态里去,那就是f[i][j][k]表示根为i,最大深度为j,已选节点状态是k的最小权值。
然后发现根那个维度其实可以不要,所以就是f[i][j]表示最大深度为i,目前状态为j的最小权值。
然后转移就是枚举j的子集k,计算出从k扩展成j的最小权值,乘上i即可。
然后发现上面那个计算k->j的最小权值,我们对于每个i都要做一次,所以可以预处理出来。
然后搞一搞一些奇怪的细节,就A了...
具体见代码。
#include <cstdio>
#include <cstring>
#include <algorithm> typedef long long LL;
const int N = , M = , INF = 0x7f7f7f7f; int G[N + ][N + ], n;
LL f[N + ][ << N], val[ << N][ << N]; inline void out(int x) {
for(int i = ; i <= ; i++) {
printf("%d", (x >> i) & );
}
printf(" ");
} int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = , x, y, z; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
if(G[x][y]) {
z = std::min(z, G[x][y]);
}
G[x][y] = G[y][x] = z;
} int lm = << n;
memset(f, 0x3f, sizeof(f));
memset(val, 0x3f, sizeof(val));
for(int i = ; i < n; i++) {
f[][ << i] = ;
}
for(int i = ; i < lm; i++) {
for(int j = (i - ) & i; j > ; j = (j - ) & i) { // j -> i
int ans = ;
for(int k = ; k < n; k++) {
if(!(i & ( << k)) || (j & ( << k))) {
continue;
}
int small = INF;
for(int l = ; l < n; l++) { // l -> k
if(!(j & ( << l)) || !G[l + ][k + ]) {
continue;
}
small = std::min(small, G[l + ][k + ]);
}
if(small == INF) {
ans = INF;
break;
}
ans += small;
}
val[j][i] = ans;
}
} for(int i = ; i <= n; i++) { // deep
for(int j = ; j < lm; j++) { // state
for(int k = (j - ) & j; k > ; k = (k - ) & j) { // subset
f[i][j] = std::min(f[i][j], f[i - ][k] + val[k][j] * i);
/*printf("%d ", i);
out(k);
out(j);
printf("%lld + %lld \n", f[i - 1][k], val[k][j] * i);*/
}
}
}
LL ans = 1ll * INF * INF;
for(int i = ; i <= n; i++) {
ans = std::min(ans, f[i][lm - ]);
}
printf("%lld", ans);
return ;
}
AC代码
发现上面一列"然后"......语文水平有待提高啊......
洛谷P3959 宝藏的更多相关文章
- 洛谷P3959——宝藏
传送门:QAQQAQ 题意: 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了$n$个深埋在地下的宝藏屋, 也给出了这$n$个宝藏屋之间可供开发的$m$条道路和它们的长度. 小明决心亲自前往挖掘所有 ...
- 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)
洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...
- 洛谷 P3959 宝藏 解题报告
P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 \(n\) 个深埋在地下的宝藏屋, 也给出了这 \(n\) 个宝藏屋之间可供开发的 \(m\) 条道路和它们的长度. 小 ...
- 2018.08.09洛谷P3959 宝藏(随机化贪心)
传送门 回想起了自己赛场上乱搜的20分. 好吧现在也就是写了一个随机化贪心就水过去了,不得不说随机化贪心大法好. 代码: #include<bits/stdc++.h> using nam ...
- 洛谷P3959 宝藏(状压dp)
传送门 为什么感觉状压dp都好玄学……FlashHu大佬太强啦…… 设$f_{i,j}$表示当前选的点集为$i$,下一次要加入的点集为$j$时,新加入的点和原有的点之间的最小边权.具体的转移可以枚举$ ...
- 洛谷P3959 宝藏(模拟退火乱搞)
题意 题目链接 题面好长啊...自己看吧.. Sol 自己想了一个退火的思路,没想到第一次交85,多退了几次就A了哈哈哈 首先把没用的边去掉,然后剩下的边从小到大排序 这样我们就得到了一个选边的序列, ...
- 洛谷 P3959 宝藏【状压dp】
一开始状态设计错了-- 设f[i][s]为当前与根节点联通状况为s,最深深度为i 转移的话枚举当前没有和根联通的点集,预处理出把这些点加进联通块的代价(枚举s中的点和当前点的连边乘以i即可),然后用没 ...
- 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)
洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...
- NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...
随机推荐
- C# Note5:使用相对路径读取文件
一.C#中使用相对路径读取配置文件 一般Solution的目录结构如下图所示: (如过看不到某些文件,可以点击 “显示所有文件” 图标) 方法一:由于生成的exe文件在bin\debug目录下,可以使 ...
- Java多线程5:Synchronized锁机制
一.前言 在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的. 二.引入Synchronized ...
- EChart.js 笔记二
交互组件 Echart.js 中交互组件比较多.例如: legend(图例).title(标题组件).visualMap(视觉映射组件).dataZoom(数据缩放组件).timeline(时间线组件 ...
- C# 23种设计模式汇总
创建型模式工厂方法(Factory Method)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节.工厂方法模式的核心是一个抽象工厂类,各种具体工 ...
- aop通配符语法
*.表示通配包名 *. == com. com.rl.ecps.service == *.*.*.*. ..表示 通配任何包及其子包 例如 com.. ==com. *.*.*. com.rl. ...
- Nginx 针对建立TCP连接优化
L:124 sysctl -a | grep file-max //通过命令查看系统最大句柄数 [root@3 ~]# sysctl -a | grep file-max fs.file-max = ...
- Redis之父表示ARM服务器没戏!
ARM表示Neoverse N1平台和E1 CPU即将发布,Neoverse N1和E1采用7nm制程,并且为服务器和通信设备增加重要提升,拥有高可扩展性.高处理量以及高性能,将分别在2020年和20 ...
- Mysql 查看连接数,状态 最大并发数(赞)
Mysql 查看连接数,状态 最大并发数(赞) -- show variables like '%max_connections%'; 查看最大连接数 set global max_connect ...
- windows新增/修改/删除系统环境变量bat示例,一键配置JAVA_HOME
setx JAVA_HOME "C:\Program Files\java\jdk1.6.0_27" /m setx classpath = ".;%JAVA_HOME% ...
- BZOJ2038[2009国家集训队]小Z的袜子(hose)——莫队
题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号 ...