#333. 【NOIP2017】宝藏

http://uoj.ac/problem/333

1、错误的$n^42^n$做法:

dp[s]表示当前的点集为s,然后从这些点中选一个做起点i,然后枚举边,然后更新dp[t|(1<<j)]。dis[s][i]表示点集为s的情况下的i号点的深度。详见代码。

为什么是错的,不满足当前最优一定是最后最优。比如下面的hack数据,正确答案应该是10420,即从4号点出发,长度为1的那条边不要。而在上面的dp中,点集为234的状态中只能从24和34转移而来,而这两个取最小值的时候,一定会算上1这条边,答案为12,而不是10这条边。导致下一步dp的时候,深度边长,导致更不优。

 #include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL; //char buf[100000], *p1 = buf, *p2 = buf;
//#define nc() p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++ inline int read() {
int x = , f = ; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch=='-') f = -;
for (; isdigit(ch); ch = getchar()) x = x * + ch - ''; return x * f;
} const int N = ;
const LL LLINF = 1e18;
const int INF = 1e9; LL dp[( << ) + ];
int mp[N][N], dis[( << ) + ][];
int n, m; LL solve(int x) {
memset(dis, , sizeof(dis));
int S = ( << n) - ; for (int s = ; s <= S; ++s) dp[s] = LLINF;
dis[ << x][x] = , dp[ << x] = ; for (int s = , t; s <= S; ++s) { // 点集
if (dp[s] == LLINF) continue;
cout << bitset<>(s) << "\n";
for (int i = ; i < n; ++i) { // 选一个点当起点
if (!((s >> i) & )) continue;
for (int j = ; j < n; ++j) { // 到达的下一个点
if (i == j || mp[i][j] == INF || ((s >> j) & )) continue;
t = s | ( << j);
cout << bitset<>(t) << "\n";
if (dp[t] > dp[s] + dis[s][i] * mp[i][j]) {
dp[t] = dp[s] + dis[s][i] * mp[i][j];
for (int k = ; k < n; ++k) dis[t][k] = dis[s][k];
dis[t][j] = dis[s][i] + ;
cout << dp[t] << "\n";
}
}
}
}
return dp[S];
} int main() {
// freopen("1.txt", "r", stdin);
// freopen("2.txt", "w", stdout);
n = read(), m = read(); for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j) mp[i][j] = INF;
for (int i = ; i <= m; ++i) {
int u = read() - , v = read() - , w = read();
mp[u][v] = min(mp[u][v], w), mp[v][u] = min(mp[v][u], w);
} LL ans = 1e18;
for (int i = ; i < n; ++i)
ans = min(ans, solve(i));
cout << ans; return ;
}
/* hack数据:
dp不满足,当前最优,不满足最后的答案最优 6 14
1 2 101
1 3 44
1 4 235
1 6 629
2 3 60
2 4 196
2 5 250
2 6 490
3 4 237
3 5 114
3 6 715
4 5 166
4 6 432
5 6 932 6 6
1 2 100
2 3 1
2 4 10
3 4 10
3 5 100
4 6 10000 */

2、那么解决上述dp中出现的dp,就需要按深度进行dp,每次枚举下一深度的所有点,子集dp。复杂度$n^33^n$

 #include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL; inline int read() {
int x = , f = ; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch=='-') f = -;
for (; isdigit(ch); ch = getchar()) x = x * + ch - ''; return x * f;
} const int N = ;
const LL LLINF = 1e18;
const int INF = 1e9; LL dp[( << ) + ][], tmp[( << ) + ], dis[N];
int mp[N][N];
int n, m; LL solve(int x) {
int S = ( << n) - ;
for (int s = ; s <= S; ++s)
for (int i = ; i <= n; ++i) dp[s][i] = LLINF;
dp[ << x][] = ; for (int s = ; s <= S; ++s) {
int r = ;
for (int i = ; i < n; ++i) dis[i] = LLINF;
for (int i = ; i < n; ++i) {
if ((s >> i) & )
for (int j = ; j < n; ++j)
if (!((s >> j) & ) && mp[i][j])
r |= ( << j), dis[j] = min(dis[j], (LL)mp[i][j]);
}
for (int t = r; t; t = (t - ) & r) {
tmp[t] = ;
for (int i = ; i < n; ++i)
if ((t >> i) & ) tmp[t] += dis[i];
}
for (int d = ; d <= n; ++d) {
if (dp[s][d] == LLINF) continue;
for (int t = r; t; t = (t - ) & r)
dp[s | t][d + ] = min(dp[s | t][d + ], dp[s][d] + tmp[t] * d);
}
}
LL ans = LLINF;
for (int i = ; i <= n; ++i) ans = min(ans, dp[S][i]);
return ans;
} int main() { n = read(), m = read(); for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j) mp[i][j] = INF;
for (int i = ; i <= m; ++i) {
int u = read() - , v = read() - , w = read();
mp[u][v] = min(mp[u][v], w), mp[v][u] = min(mp[v][u], w);
} LL ans = 1e18;
for (int i = ; i < n; ++i)
ans = min(ans, solve(i));
cout << ans; return ;
}

3、随机化算法

#333. 【NOIP2017】宝藏的更多相关文章

  1. 【比赛】NOIP2017 宝藏

    这道题考试的时候就骗了部分分.其实一眼看过去,n范围12,就知道是状压,但是不知道怎么状压,想了5分钟想不出来就枪毙了状压,与AC再见了. 现在写的是状压搜索,其实算是哈希搜索,感觉状压DP理解不了啊 ...

  2. [NOIP2017]宝藏 状压DP

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

  3. [NOIP2017]宝藏 子集DP

    题面:[NOIP2017]宝藏 题面: 首先我们观察到,如果直接DP,因为每次转移的代价受上一个状态到底选了哪些边的影响,因此无法直接转移. 所以我们考虑分层DP,即每次强制现在加入的点的距离为k(可 ...

  4. NOIP2017宝藏 [搜索/状压dp]

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

  5. NOIP2017 - 宝藏

    LibreOJ链接 Description 给出一个\(n(n\leq12)\)个点\(m(m\leq1000)\)条边的带权无向图,求该图的一棵生成树,使得其边权×该边距根的深度之和最小. Solu ...

  6. Luogu 3959 [NOIP2017] 宝藏

    NOIP2017最后一道题 挺难想的状压dp. 受到深度的条件限制,所以一般的状态设计带有后效性,这时候考虑把深度作为一维,这样子可以保证所有状态不重复计算一遍. 神仙预处理:先处理出一个点连到一个集 ...

  7. 洛谷P3959 [NOIP2017]宝藏

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

  8. NOIP2017 宝藏 题解报告【状压dp】

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

  9. 【洛谷P3959】[NOIP2017] 宝藏

    宝藏 题目链接 首先,打了一个prim,得了45分 #include<iostream> #include<cstring> #include<cstdio> #i ...

  10. [NOIP2017] 宝藏 【树形DP】【状压DP】

    题目分析: 这个做法不是最优的,想找最优解请关闭这篇博客. 首先容易想到用$f[i][S][j]$表示点$i$为根,考虑$S$这些点,$i$的深度为$j$情况的答案. 转移如下: $f[i][S][j ...

随机推荐

  1. 「bzoj 4180: 字符串计数」

    题目 真是一道好题 首先根据一个非常显然的贪心,如果给出了一个串\(S\),我们如何算最小操作次数呢 非常简单,我们直接把\(S\)拉到\(T\)的\(SAM\)上去跑,如果跑不动了就停下来,重新回到 ...

  2. urllib库基本使用

    #导入urllib库 import urllib.request #打开网址 file=urllib.request.urlopen("http://www.sohu.com/", ...

  3. Odoo日历视图

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9280604.html 一:日历视图定义 根元素为<calendar>. 主要的属性有:    co ...

  4. [Python 多线程] Timer定时器/延迟执行、Event事件 (七)

    Timer继承子Thread类,是Thread的子类,也是线程类,具有线程的能力和特征.这个类用来定义多久执行一个函数. 它的实例是能够延迟执行目标函数的线程,在真正执行目标函数之前,都可以cance ...

  5. 关于numpy mean函数的axis参数

    import numpy as np X = np.array([[1, 2], [4, 5], [7, 8]]) print np.mean(X, axis=0, keepdims=True) pr ...

  6. python 装饰器 传递参数简单案例

    def debug(func): def wrapper(*args, **kwargs): # 指定宇宙无敌参数 print "[DEBUG]: enter {}()".form ...

  7. HDU 3695 Computer Virus on Planet Pandora (AC自己主动机)

    题意:有n种病毒序列(字符串),一个模式串,问这个字符串包括几种病毒. 包括相反的病毒也算.字符串中[qx]表示有q个x字符.具体见案列. 0 < q <= 5,000,000尽然不会超, ...

  8. 使用yum命令时提示:Another app is currently holding the yum lock

    yum正在使用,用kill命令杀死进程就可以了. 1.查看yum使用进程号 ps aux|grep yum 2.杀死进程 kill -9 进程号

  9. 【.net开发者自学java系列】使用Eclipse开发SpringMVC(1)

    第一篇随笔,有点紧张.有错别字是正常的.... 好了,自我描述下.我是一个有几年.net开发经验的老菜鸟.是的,老菜鸟.别跟我讨论底层,别跟我讨论协议.TMD啥都不会. 为什么要学JAVA,我也不想, ...

  10. Unbnutu下安装Apache,Mysql,php,phpmyadmin

    先写一键部署脚本,肯定是先要知道如何手动安装Apache,Mysql,php,phpmyadmin 一  Apache2的安装 apt install apache2 安装好之后,手动看一下apach ...