洛谷P3959——宝藏
传送门:QAQQAQ
题意:
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了$n$个深埋在地下的宝藏屋, 也给出了这$n$个宝藏屋之间可供开发的$m$条道路和它们的长度。
小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。
小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。
在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。
新开发一条道路的代价是:
$L*K$
L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。
请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。
思路:看数据范围,$n<=12$,很自然而然想到状态压缩。
我们用$dp[i][mask]$保存从$i$开始挖,当前状态为$mask$的最少花费
现在的难点在于如何处理$K$——这个点在这棵树中的深度。
我们用$dis[i][mask]$保存在当前状态为$mask$,且当前答案最优,第$i$个点在树中的深度加一(为什么要加一?转移时好看一点嘛~~~)
我们可能会担心,当前$mask$最佳的连图方式无法保证它扩展到下一个节点的答案最优,但考虑到对于要被更新的$mask'$,总有一种之前最佳的$mask$连上一条边会使当前$mask'$答案最优。
而且被更新的$mask'$一定大于$mask$,所以每一个$dp[i][mask]$都会被更新到最优,那么我们在最后更新一下$ans$就可以啦~~~
代码:(之前并没有保存对于每一个$mask$的$dis$,导致可能最优连图和点的深度不对应,甚至答案会偏小(详见我洛谷上40分代码,即保存的是最小深度,而不是最优连图下的深度))
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=;
const ll inf=(int)2e9; ll dp[][],n,m;
ll E[][],dis[][]; void checkmin(ll &x,ll y)
{
if(x>y) x=y;
} int main()
{
scanf("%lld%lld",&n,&m);
for(int i=;i<n;i++)
{
for(int j=;j<n;j++) E[i][j]=inf;
}
int full=(<<n);
for(int i=;i<n;i++)
for(int j=;j<full;j++) dp[i][j]=inf;
for(int i=;i<=m;i++)
{
int x,y; ll z;
scanf("%d%d%lld",&x,&y,&z);
x--; y--; if(x==y) continue;
E[x][y]=min(z,E[x][y]);
E[y][x]=min(z,E[y][x]);
}
for(int start=;start<n;start++)
{
dis[(<<start)][start]=; dp[start][(<<start)]=;
for(int mask=;mask<full;mask++)
{
if(!(mask>>start)&) continue;
for(int from=;from<n;from++)
{
if(!(mask>>from)&) continue;
for(int to=;to<n;to++)
{
if((mask>>to)&) continue;
if(dp[start][mask]==inf||dis[mask][from]==) continue;
if(E[from][to]==inf) continue;
int mask1=mask|(<<to);
if(dp[start][mask1]>dp[start][mask]+dis[mask][from]*E[from][to])
{
dp[start][mask1]=dp[start][mask]+dis[mask][from]*E[from][to];
for(int p=;p<n;p++) dis[mask1][p]=dis[mask][p];
dis[mask1][to]=dis[mask][from]+;
}
}
}
}
}
ll ans=inf;
for(int i=;i<n;i++) checkmin(ans,dp[i][full-]);
cout<<ans<<endl;
return ;
}
(本来以为这种做法是错的,兴致勃勃地造了一组数据结果发现hack不掉。。。现在才真正懂)
洛谷P3959——宝藏的更多相关文章
- 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)
洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...
- 洛谷 P3959 宝藏 解题报告
P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 \(n\) 个深埋在地下的宝藏屋, 也给出了这 \(n\) 个宝藏屋之间可供开发的 \(m\) 条道路和它们的长度. 小 ...
- 洛谷P3959 宝藏
去年NOIP第二毒瘤(并不)的题终于被我攻克了,接下来就只剩noip难度巅峰列队了. 首先说一下三种做法:随机化,状压DP和搜索. 前两种做法我都A了,搜索实在是毒瘤,写鬼啊. 有些带DFS的记忆化搜 ...
- 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 题意 给定一个 ...
随机推荐
- Python 生成json文件
1.数据准备 数据下载 2.python代码 import datetime import os import mssqlhelper ms = mssqlhelper.MSSQL(host=&quo ...
- 静态栈-------C语言
/***************************************************** Author:Simon_Kly Version:0.1 Date: 20170520 D ...
- 【HTML】框架集(Framesets)
1.Frameset的使用 所谓框架便是网页画面分成几个框窗,同时取得多个 URL.只 要 <FRAMESET> <FRAME> 即可,而所有框架标记 要放在一个总起的 htm ...
- 在Python的列表中利用remove()方法删除元素的教程
在Python的列表中利用remove()方法删除元素的教程 这篇文章主要介绍了在Python的列表中利用remove()方法删除元素的教程,是Python入门中的基础知识,注意其和pop()方法的区 ...
- C++——代码风格
google代码风格 1.使用安全的分配器(allocator),如scoped_ptr,scoped_array 2.测试用的,其他的不能用: 2.1 友元 2.2 C++异常 2.3 RTTI 3 ...
- js文本框焦点自动聚焦到下个文本框
HTML: <form> <input type="text" name="text1" maxlength="3" si ...
- 高程(三)----数组Array
一.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上 ...
- ArcGis基础——动态显示面要素的面积值
很基础,不赘述. 1.在catalog(目录)新建一个PersonalGeoDatabase(个人地理数据库),导入需要处理的Shapefile文件. 坐标系统,存储路径与命名根据自己需求设定 2.直 ...
- sanic之websocket路由
在某些时候,需要建立websocket路由,来建立长链接,来实时传输数据,就比如一些聊天应用,就有实时音视频,需要实时传出状态 在sanic框架中支持两种websocket路由方式,有一种是再app中 ...
- C语言指针变量的长度
#include <stdio.h> int main() { /********************************************* * * 指针的长度:不同机器可 ...