【题目描述】

参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋,也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。

小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远,也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路则相对容易很多。

小明的决心感动了考古挖掘的赞助商, 赞助商决定免费赞助他打通一条从地面到某个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。

在此基础上, 小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏屋之间的道路无需再开发。

新开发一条道路的代价是:

这条道路的长度 × 从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋)。

请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代价最小,并输出这个最小值。

【输入格式】

第一行两个用空格分离的正整数 n 和 m,代表宝藏屋的个数和道路数。

接下来 m 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏屋的编号(编号为 1~n),和这条道路的长度 v。

【输出格式】

输出共一行,一个正整数,表示最小的总代价。

【样例输入1】

4 5
1 2 1
1 3 3
1 4 1
2 3 4
3 4 1

【样例输出1】

4

【样例1提示】

【样例输入2】

4 5
1 2 1
1 3 3
1 4 1
2 3 4
3 4 2

【样例输出2】

5

【样例2提示】

【数据规模】

对于 20%的数据:

保证输入是一棵树, 1≤n≤8, v≤5000 且所有的 v 都相等。

对于 40%的数据:

1≤n≤8, 0≤m≤1000, v≤5000 且所有的 v 都相等。

对于 70%的数据:

1≤n≤8, 0≤m≤1000, v≤ 5000

对于 100%的数据:

1≤n≤12, 0≤m≤1000, v≤ 500000

就把这道NOIP题当成回坑以后第一篇博吧(丢人

数据范围一眼状压DP,然而好像已经忘了DP怎么玩了

一顿胡乱撕烤,脑洞出一个常数巨大的解法。

F[a]表示联通状态为a的最优方案,G[a][]记录状态a的最优方案对应的每个结点深度,枚举边更新

注意到边数远超过完全图,可以预处理删掉无用边。

然而状态挂在了vector上常数过大,在洛谷上T了一个点,开O2可以A,假装自己过掉了(逃

(UPD6.15 突然发现代码放错了 噫呜呜噫)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
int n,m;
const int mxn=;
const int N=<<;
struct edge{
int u,v,w;
int next;
}e[mxn<<];
int hd[mxn],cnt=;
void add_edge(int u,int v,int w){
e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
e[cnt].next=hd[u];hd[u]=cnt;
return;
}
int f[N];
struct node{
int dep[];
};
vector<node>g[N];
// node tt,a;
void solve(){
int tmp=<<n;
for(int i=;i<=n;i++){
f[<<(i-)]=;
tt.dep[i-]=;
g[<<(i-)].push_back(tt);
tt.dep[i-]=;
}
for(int i=;i<tmp;i++){
// printf("tmp:%d %d\n",i,f[i]);
for(int u=;u<n;u++){
if( (i&(<<u)) ){
// printf(" u:%d\n",u);
for(int now=;now<g[i].size();now++){
// printf(" now:%d\n",now);
for(int h=hd[u];h;h=e[h].next){ int v=e[h].v;
// printf(" v:%d\n",v);
if(i&(<<v))continue;
// printf(" v:%d\n",v); int tar=i|(<<v);
// printf(" tar:%d\n",tar);
if(f[tar] > f[i] + e[h].w*g[i][now].dep[u] ){
f[tar] = f[i] + e[h].w*g[i][now].dep[u];
a=g[i][now];
a.dep[v]=g[i][now].dep[u]+;
g[tar].clear();
g[tar].push_back(a);
a.dep[v]=;
}
else if(f[tar]== (f[i] + e[h].w*g[i][now].dep[u])){
a=g[i][now];
a.dep[v]=g[i][now].dep[u]+;
g[tar].push_back(a);
a.dep[v]=;
}
}
}
}
}
}
return;
}
int mp[][];
int main(){
int i,j,u,v,w;
scanf("%d%d",&n,&m);
memset(mp,0x3f,sizeof mp);
for(i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
--u;--v;
mp[u][v]=mp[v][u]=min(mp[u][v],w);
}
for(i=;i<n;i++)
for(j=;j<n;j++)
if(mp[i][j]<0x3f3f3f3f)
add_edge(i,j,mp[i][j]);
memset(f,0x3f,sizeof(f));
solve();
printf("%d\n",f[(<<n)-]);
return ;
}

更好的解法是f[a][dep]记录联通状态为a,最深的点深度为dep的最优解,进行转移。

洛谷P3959 [NOIP2017]宝藏的更多相关文章

  1. 洛谷 P3959 NOIP2017 宝藏 —— 状压搜索

    题目:https://www.luogu.org/problemnew/show/P3959 搜索: 不是记忆化,而是剪枝: 邻接矩阵存边即可,因为显然没有那么多边. 代码如下: #include&l ...

  2. 洛谷$P3959\ [NOIp2017]$ 宝藏 状压$dp$

    正解:状压$dp$ 解题报告: 传送门$QwQ$ $8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$ 发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j} ...

  3. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

  4. 【洛谷P3959】宝藏

    题目大意:比较复杂,点 这里 看题. 题解:对于状态压缩 dp 来讲,阶段的确立十分重要.本题中,采用以层次为阶段进行状压 dp. 设状态 \(f[i][S]\) 表示开凿到深度 \(i\),当前已经 ...

  5. NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...

  6. 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)

    洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...

  7. 洛谷P3959——宝藏

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

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

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

  9. 洛谷 P3959 宝藏 解题报告

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

随机推荐

  1. Beta阶段团队项目开发篇章1

    例会时间:2016.12.1 例会照片: 个人工作: 任务分配: 组员 任务内容 李文涛 编写并发布调查问卷 姬索肇 审核并传播调查问卷 韩慧敏 审核并传播调查问卷 任务截止时间 2016.12.4 ...

  2. 区别mouseover与mouseenter?

    区别mouseover与mouseenter? * mouseover: 在移入子元素时也会触发, 对应mouseout,进入子元素的时候,父元素显示离开状态 * mouseenter: 只在移入当前 ...

  3. node path模块

    一.在nodejs中path模块时使用频率很高的模块,其中不乏有很多API写得很模糊,但仔细琢磨下来,也不是很难理解. 1.获取文件所在路径 var path = require('path'); v ...

  4. Windows下 OpenSSL的安装与简单使用

    1. openssl的最新版本 最新版本是 openssl1.1.1 官方地址 https://www.openssl.org/source/ TLS1.3的协议(RFC8446)在2018.8.12 ...

  5. 内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理][转载]

    http://www.cnblogs.com/JCSU/articles/1051579.html 一. 在c中分为这几个存储区1.栈 - 由编译器自动分配释放2.堆 - 一般由程序员分配释放,若程序 ...

  6. BZOJ5105 CodePlus2017晨跑

    这个题???我WA了两发??? #include<iostream> #include<cstdio> #include<cmath> #include<cs ...

  7. BZOJ3203 SDOI2013保护出题人(三分)

    给a做一个前缀和,那么现在每次所查询的就是(sn-sk)/(bn+nd-(k+1)d)的最大值.这个式子可以看成是(bn+nd,sn)和((k+1)d,sk)所成直线的斜率. 脑补一条直线不断减小斜率 ...

  8. MT【157】至少一个小于1

    若函数$f(x)=x^2+ax+b$有两个不等实数根$x_1,x_2$,且$1<x_1<x_2<3$,那么$f(1),f(3)中$    (      )A.只有一个小于1 B.至少 ...

  9. 分享关于js解析URL中的参数的方法

    function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&] ...

  10. 洛谷 P1356 数列的整数性 解题报告

    P1356 数列的整数性 题目描述 对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式,也就可以计算出表达式的值.比如,现在有一个整数数列:17,5, ...