洛谷 P3959 宝藏 解题报告
P3959 宝藏
题目描述
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 \(n\) 个深埋在地下的宝藏屋, 也给出了这 \(n\) 个宝藏屋之间可供开发的 \(m\) 条道路和它们的长度。
小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。
小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。
在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。
新开发一条道路的代价是:
\(\mathrm{L} \times \mathrm{K}\)
L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。
请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。
输入输出格式
输入格式:
第一行两个用空格分离的正整数 \(n,m\) ,代表宝藏屋的个数和道路数。
接下来 \(m\) 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 \(1-n\) ),和这条道路的长度 \(v\) 。
输出格式:
一个正整数,表示最小的总代价。
数据规模与约定
对于 \(20\%\) 的数据: 保证输入是一棵树, \(1 \le n \le 8\), \(v \le 5000\) 且所有的 \(v\) 都相等。
对于 \(40\%\) 的数据: \(1 \le n \le 8\) , \(0 \le m \le 1000\) , \(v \le 5000\) 且所有的 \(v\) 都相等。
对于 \(70\%\) 的数据: \(1 \le n \le 8\), \(0 \le m \le 1000\), \(v \le 5000\)
对于 \(100\%\) 的数据: \(1 \le n \le 12\),\(0 \le m \le 1000\) , \(v \le 500000\)
首先,这个题暴力性价比超级高哎
70分pts
#include <cstdio>
#include <cstring>
int min(int x,int y){return x<y?x:y;}
const int N=15;
const int inf=0x3f3f3f3f;
int g[N][N],n,m;
void init()
{
scanf("%d%d",&n,&m);
memset(g,0x3f,sizeof(g));
for(int u,v,w,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
g[u][v]=min(g[u][v],w);
g[v][u]=g[u][v];
}
}
int cho[N],dep[N],ans=inf;
void dfs(int cnt,int cost)
{
if(cost>=ans) return;
if(cnt==n) {ans=cost;return;}
for(int i=1;i<=n;i++)
if(!cho[i])
{
cho[i]=1;
for(int j=1;j<=n;j++)
if(cho[j]&&g[i][j]!=inf)
{
dep[i]=dep[j]+1;
dfs(cnt+1,cost+dep[j]*g[i][j]);
}
cho[i]=0;
}
}
int main()
{
init();
for(int i=1;i<=n;i++)
{
dep[i]=1,cho[i]=1;
dfs(1,0);
cho[i]=0;
}
printf("%d\n",ans);
return 0;
}
在此基础上,爬山退火甚至剪枝都可以艹过去了,不过我们稍微讨论一下正解。
首先我们得至少按照层数来做,因为它和代价相关。
一个比较好搞出来的想法就是\(dp_{S,d}\)代表已经选中子树\(S\)且其的深度为\(d\)的时候的最小代价。
但是我们发现转移的时候我们需要把点接在最后一层,我们是不是一个搞一个存储最后一层点集的东西呢??
不行,这样的复杂度还不如直接暴力。
我们强行接点好吗,哪怕接在了不是最后一层的点上,根据题意我们认为道路长度不为负,我们的答案只会大不会小。这样就足够了,因为所有的状态都会被找到,所以非最优的局部不会错过最优解。
尝试列出转移方程
\(dp_{S,d}=min(dp_{las,d-1}+(d-1)\times cost_{las,S})\)
直接遍历两个集合显然不行,我们可以尝试枚举一个S,然后DFS它的子集。而实际上,遍历子集有更方便的写法
对于费用数组\(cost[i][j]\),我们先求出某个集合对单个点连接的费用(涉及决策),然后更新集合对集合的费用。注意同样要枚举子集。
还要注意,正无穷的费用不能参与更新,否则会爆int
Code:
#include <cstdio>
#include <cstring>
const int inf=0x3f3f3f3f;
const int N=12;
int min(int x,int y){return x<y?x:y;}
int g[N+1][N+1],dp[1<<N][N+1],cost[1<<N][1<<N],c[1<<N][13],n,m,ans=inf;
int main()
{
scanf("%d%d",&n,&m);
memset(g,0x3f,sizeof(g));
for(int u,v,w,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
g[u][v]=min(g[u][v],w);
g[v][u]=g[u][v];
}
memset(c,0x3f,sizeof(c));
memset(cost,0x3f,sizeof(cost));
for(int s=1;s<1<<n;s++)
for(int i=1;i<=n;i++)
{
int mi=inf;
for(int j=0;j<n;j++)
if((s>>j)&1)
mi=min(mi,g[j+1][i]);
c[s][i]=mi;
}
for(int t=1;t<1<<n;t++)
for(int s=t-1&t;s;s=s-1&t)
{
cost[s][t]=0;
int k=t-s;
for(int j=0;j<n;j++)
if((k>>j)&1)
{
if(c[s][j+1]==inf) {cost[s][t]=inf;break;}
cost[s][t]+=c[s][j+1];
}
}
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<n;i++)
dp[1<<i][1]=0;
ans=min(ans,dp[(1<<n)-1][1]);
for(int d=2;d<=n;d++)
{
for(int sta=0;sta<1<<n;sta++)
for(int las=sta-1&sta;las;las=las-1&sta)
if(dp[las][d-1]!=inf&&cost[las][sta]!=inf)
dp[sta][d]=min(dp[sta][d],dp[las][d-1]+(d-1)*cost[las][sta]);
ans=min(ans,dp[(1<<n)-1][d]);
}
printf("%d\n",ans);
return 0;
}
2018.8.4
洛谷 P3959 宝藏 解题报告的更多相关文章
- 洛谷P3959——宝藏
传送门:QAQQAQ 题意: 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了$n$个深埋在地下的宝藏屋, 也给出了这$n$个宝藏屋之间可供开发的$m$条道路和它们的长度. 小明决心亲自前往挖掘所有 ...
- 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)
洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...
- 洛谷 P2058 海港 解题报告
P2058 海港 题目描述 小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况: ...
- 洛谷 P3956 棋盘 解题报告
P3956 棋盘 题目描述 有一个\(m×m\)的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的最左上角走到棋盘的最右下角. 任何一个时刻,你所站在的位置必须是有颜色的(不能 ...
- 洛谷 P1979 华容道 解题报告
P1979 华容道 题目描述 小\(B\)最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时 ...
- BZOJ 3545 / 洛谷 P4197 Peaks 解题报告
P4197 Peaks 题目描述 在\(\text{Bytemountains}\)有\(N\)座山峰,每座山峰有他的高度\(h_i\).有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个 ...
- 虔诚的墓主人(BZOJ1227)(洛谷P2154)解题报告
题目描述 小W是一片新造公墓的管理人.公墓可以看成一块N×M的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地. 当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地. ...
- 洛谷 P1076 寻宝 解题报告
P1076 寻宝 题目描述 传说很遥远的藏宝楼顶层藏着诱人的宝藏.小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书.说明书的内容如下: 藏宝楼共有\( ...
- 洛谷P3959 宝藏
去年NOIP第二毒瘤(并不)的题终于被我攻克了,接下来就只剩noip难度巅峰列队了. 首先说一下三种做法:随机化,状压DP和搜索. 前两种做法我都A了,搜索实在是毒瘤,写鬼啊. 有些带DFS的记忆化搜 ...
随机推荐
- Appium_Python_API说明
Appium_Python_API 1.contexts contexts(self): Returns the contexts within the current session. 返回当前会话 ...
- PyCharm 2018 最新激活方式总结(最新最全最有效)!!!
PyCharm 2018 最新激活方式总结(最新最全最有效!!!) pycharm2018 是目前python编程的主要应用工具,具有非常广泛的应用,不过对于它的破解一直比较麻烦,这里我为大家提供了三 ...
- 【转】关于cocos2dx+lua注册事件函数详解
转载:http://www.taikr.com/article/1605 registerScriptTouchHandler 注册触屏事件registerScriptTapHandler注册点击事件 ...
- appium关键字:
## Appium 服务关键字 <expand_table> |关键字|描述|实例||----|-----------|-------||`automationName`|你想使用的自动化 ...
- dotnetframe的清理工具
微软的产品一向不敢恭维,卸载都没有办法卸载干净,卸载又慢又不彻底,dotnet被我卸载之后还有注册表残留以至于无法重新安装. .NET Framework Cleanup Tool真的很好用,全部版本 ...
- vmware中三种网络连接方式
原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note vmw ...
- 创新手机游戏《3L》开发点滴(3)——道具、物品、装备表设计 V2(最终版)
我们正在开发一款新手游,里面有道具,之前也写了一篇博文记录了下我们的设计思路,但是国庆到了,于是我有了时间继续纠结这个问题. 其实我主要是在到底是用mysql还是mongodb上纠结.这个复杂.痛苦. ...
- array.some() 方法兼容ie8
在第 5 版时,some 被添加进 ECMA-262 标准:这样导致某些实现环境可能不支持它.你可以把下面的代码插入到脚本的开头来解决此问题,从而允许在那些没有原生支持它的实现环境中使用它.该算法是 ...
- Java 单例模式探讨
以下是我再次研究单例(Java 单例模式缺点)时在网上收集的资料,相信你们看完就对单例完全掌握了 Java单例模式应该是看起来以及用起来简单的一种设计模式,但是就实现方式以及原理来说,也并不浅显哦. ...
- pxe+kickstart无人值守安装
常用软件安装及使用目录 第1章 以前是怎么安装系统的 l 光盘(ISO文件,光盘的镜像文件)===>每一台物理机都得给一个光驱,如果用外置光驱的话,是不是每台机器都需要插一下 l U盘:ISO镜 ...