NOIP2017提高组day2 - T2:宝藏

题目链接

[NOIP2017 提高组] 宝藏

题目描述

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

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

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

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

新开发一条道路的代价是 L × K \mathrm{L} \times \mathrm{K} L×K。其中 L L L 代表这条道路的长度, K K K 代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

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

输入格式

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

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

输出格式

一个正整数,表示最小的总代价。

样例 #1

样例输入 #1

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

样例输出 #1

4

样例 #2

样例输入 #2

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

样例输出 #2

5

提示

在这里插入图片描述

【样例解释 1 1 1

小明选定让赞助商打通了 1 1 1 号宝藏屋。小明开发了道路 1 → 2 1 \to 2 12,挖掘了 2 2 2 号宝藏。开发了道路 1 → 4 1 \to 4 14,挖掘了 4 4 4 号宝藏。还开发了道路 4 → 3 4 \to 3 43,挖掘了 3 3 3 号宝藏。

工程总代价为 1 × 1 + 1 × 1 + 1 × 2 = 4 1 \times 1 + 1 \times 1 + 1 \times 2 = 4 1×1+1×1+1×2=4

【样例解释 2 2 2

小明选定让赞助商打通了 1 1 1 号宝藏屋。小明开发了道路 1 → 2 1 \to 2 12,挖掘了 2 2 2 号宝藏。开发了道路 1 → 3 1 \to 3 13,挖掘了 3 3 3 号宝藏。还开发了道路 1 → 4 1 \to 4 14,挖掘了 4 4 4 号宝藏。

工程总代价为 1 × 1 + 3 × 1 + 1 × 1 = 5 1 \times 1 + 3 \times 1 + 1 \times 1 = 5 1×1+3×1+1×1=5

【数据规模与约定】

对于 20 % 20\% 20% 的数据: 保证输入是一棵树, 1 ≤ n ≤ 8 1 \le n \le 8 1n8 v ≤ 5 × 1 0 3 v \le 5\times 10^3 v5×103 且所有的 v v v 都相等。

对于 40 % 40\% 40% 的数据: 1 ≤ n ≤ 8 1 \le n \le 8 1n8 0 ≤ m ≤ 1 0 3 0 \le m \le 10^3 0m103 v ≤ 5 × 1 0 3 v \le 5\times 10^3 v5×103 且所有的 v v v 都相等。

对于 70 % 70\% 70% 的数据: 1 ≤ n ≤ 8 1 \le n \le 8 1n8 0 ≤ m ≤ 1 0 3 0 \le m \le 10^3 0m103 v ≤ 5 × 1 0 3 v \le 5\times 10^3 v5×103

对于 100 % 100\% 100% 的数据: 1 ≤ n ≤ 12 1 \le n \le 12 1n12 0 ≤ m ≤ 1 0 3 0 \le m \le 10^3 0m103 v ≤ 5 × 1 0 5 v \le 5\times 10^5 v5×105

算法思想

根据题目描述,小明需要考虑如何开凿宝藏屋之间的道路,并且两个已经被挖掘过的宝藏屋之间的道路无需再开发,也就是说题目求的是一棵生成树,使得代价和最小。

由于开发一条道路的代价与道路的长度 L L L和从起点到宝藏屋所经过的宝藏屋的数量(即宝藏屋的深度 K K K有关,因此不能使用最小生成树的算法进行计算。

考虑到结点数 n n n的范围较小( 1 ≤ n ≤ 12 1 \le n \le 12 1n12),考虑使用状态压缩动态规划解决。

状态表示

S S S表示当前生成树的状态,其二进制位上的 0 0 0 1 1 1表示是否包含相应的宝藏屋。例如,当有 0 、 1 、 2 、 3 、 4 0、1、2、3、4 01234一共 5 5 5个宝藏屋时,目前生成树已经包含了 0 、 3 、 4 0、3、4 034,那么 s t a t e = ( 11001 ) 2 state=(11001)_2 state=(11001)2 s t a t e state state的范围从 0 ∼ 2 n − 1 0\sim 2^n-1 02n1

状态除了跟当前生成树的情况有关,还与树的深度有关,用 i i i表示当前生成树的深度,其中起点的深度为 0 0 0

因此, f [ s t a t e ] [ i ] f[state][i] f[state][i]表示当前生成树状态为 s t a t e state state、并且树的深度为 i i i时,工程总代价的最小值。

最终结果为包含所有宝藏屋时,对于不同深度的生成树取最小值,即 m i n { f [ 2 n − 1 ] [ i ] } min\{f[2^n-1][i]\} min{f[2n1][i]},其中 0 ≤ i < n 0\le i<n 0i<n

状态计算

状态转移

要计算当前状态 f [ s t a t e ] [ i ] f[state][i] f[state][i],从最后一步分析,即从第 i − 1 i-1 i1层可以转移到第 i i i

  • 不妨设第 i i i层点集(宝藏屋)的状态为 s s s s s s是状态 s t a t e state state的一个子集
  • 如果前 i − 1 i-1 i1层的点集的状态为 t t t,那么 t = s t a t e ⊕ s t= state\oplus s t=states(异或运算 x o r xor xor

因此:
f [ s t a t e ] [ i ] = m i n { f [ t ] [ i − 1 ] + c o s t } f[state][i] = min\{f[t][i-1]+cost\} f[state][i]=min{f[t][i1]+cost}

计算代价

其中 c o s t cost cost表示第 i i i层所有点(宝藏屋)到第 i − 1 i-1 i1层的最小代价。那么 c o s t = L × K cost = L\times K cost=L×K,其中 L L L表示第 i i i层所有点到第 i − 1 i-1 i1层的长度之和; K K K代表从起点到第 i i i的深度。

为了能够快速计算 L L L,可以预处理得到任一点到所有集合的最小长度,不妨设 g [ i ] [ s t a t e ] g[i][state] g[i][state]表示点 i i i到点集 s t a t e state state的最小长度。那么 g [ i ] [ s t a t e ] g[i][state] g[i][state]等于点 i i i到点集 s t a t e state state中任意一点的最短距离。

算法流程

枚举所有要计算的点集 s t a t e state state,在计算当前状态 f [ s t a t e ] [ i ] f[state][i] f[state][i]时:

  • 要枚举 s t a t e state state的所有子集,即第 i i i层的点集状态 s s s
    • 计算出第 i i i层的所有点到第 i − 1 i-1 i1层的最小长度之和 L L L
    • 然后再枚举深度 i i i,计算 f [ s t a t e ] [ i ] f[state][i] f[state][i]

初始状态

  • 求的是工程总代价最小值,因此 f f f数组应初始化尽可能大
  • 可以打通任意一个宝藏屋到地面的通道到,因此对于任意一点 i i i,在生成树中只包含该点、且深度为 0 0 0时,其最小值应该为 0 0 0,即 f [ 1 < < i ] [ 0 ] = 0 f[1<<i][0]=0 f[1<<i][0]=0

时间复杂度

时间复杂度包含两部分:

  • 预处理 g [ i ] [ s t a t e ] g[i][state] g[i][state]的时间复杂度为 O ( n 2 × 2 n ) O(n^2\times2^n) O(n2×2n)
    • 状态数为 n × 2 n n\times2^n n×2n
    • 计算过程中需要枚举任意集合 s t a t e state state中任意点,时间复杂度 O ( n ) O(n) O(n)
  • 计算状态 f [ s t a t e ] [ i ] f[state][i] f[state][i]的时间复杂度为 O ( n 2 × 3 n ) O(n^2\times3^n) O(n2×3n)
    • 计算过程中需要枚举集合的所有子集。考虑对于元素个数为 k k k的子集,一共有 C n k C_n^k Cnk种情况,每个子集有 2 k 2^k 2k个子集,那么需要枚举的次数为 ∑ k = 0 n C n k × 2 k \sum_{k=0}^nC_n^k\times2^k k=0nCnk×2k。利用二项式定理: ∑ k = 0 n C n k × 2 k = ( 1 + 2 ) n = 3 n \sum_{k=0}^nC_n^k\times2^k=(1+2)^n=3^n k=0nCnk×2k=(1+2)n=3n
    • 对于每个子集需要 n 2 n^2 n2次计算来算出剩余点到子集中的最小长度。

二项式定理 ( x + y ) n = C n 0 x n y 0 + C n 1 x n − 1 y 1 + C n 2 x ( n − 2 ) y 2 + . . . + C n n − 1 x 1 y n − 1 + C n n x 0 y n (x+y)^n=C_n^0x^ny^0+C_n^1x^{n-1}y^1+C_n^2x^(n-2)y^2+...+C_n^{n-1}x^1y^{n-1}+C_n^nx^0y^n (x+y)n=Cn0xny0+Cn1xn1y1+Cn2x(n2)y2+...+Cnn1x1yn1+Cnnx0yn

代码实现

#include <iostream>
#include <cstring>
using namespace std;const int N = 12, M = 1 << N, INF = 0x3f3f3f3f;
//g[i][state]表示点i到集合state的最小长度
int w[N][N], g[N][M];
//f[state][i]表示当前生成树状态为state、并且树的深度为i时,工程总代价的最小值
int f[M][N];
int main()
{int n, m;cin >> n >> m;memset(w, 0x3f, sizeof w);while(m --){int a, b, c;cin >> a >> b >> c;//点的编号从0开始,以便处理点集a --, b --;//有重边,所以取最小值w[a][b] = w[b][a] = min(w[a][b], c);}//预处理任一点到所有集合的最小长度memset(g, 0x3f, sizeof g);for(int i = 0; i < n; i ++)for(int state = 0; state < 1 << n; state ++)//枚举state中的点for(int k = 0; k < n; k ++)if(state >> k & 1)//更新i到集合state长度的最小值g[i][state] = min(g[i][state], w[i][k]); //初始状态memset(f, 0x3f, sizeof f);//以i点为起点到达深度0的最小代价为0for(int i = 0; i < n; i ++) f[1 << i][0] = 0;//状态计算for(int state = 1; state < 1 << n; state ++){//枚举state的子集sfor(int s = state - 1 & state; s != 0; s = s - 1 & state){//t表示前i-1层的点集状态int t = state ^ s, L = 0;//枚举第i层所有点,计算第i层的所有点到第i-1层的最小长度之和Lfor(int k = 0; k < n; k ++){if(s >> k & 1) //点k在第i层的集合中{L += g[k][t]; //累加最后一层所有点到上一层的长度if(L >= INF) break; //点k到不了第i-1层的所有点}}if(L >= INF) continue; //子集s中存在点无法到达第i-1层//枚举深度,计算当前状态f[state][i]for(int i = 1; i < n; i ++)f[state][i] = min(f[state][i], f[t][i - 1] + L * i);}}//结果为包含所有宝藏屋时,对于不同深度的生成树取最小值int ans = INF;for(int i = 0; i < n; i ++)ans = min(ans, f[(1 << n) - 1][i]);cout << ans;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/220085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【沐风老师】科研绘图3DMAX病毒建模教程

3dMax在科研绘图方面也有广泛的应用&#xff0c;本教程就给大家讲解病毒的建模方法&#xff0c;下面直接进入教程&#xff1a; 3dMax病毒建模方法&#xff1a; 1.启动3dMax&#xff0c;在视口中创建一个“几何球体”。方法&#xff1a;右边命令面板->创建->几何体->…

MySQL中EXPLAIN执行计划的分析

一. 执行计划能告诉我们什么&#xff1f; SQL如何使用索引联接查询的执行顺序查询扫描的数据函数 二. 执行计划中的内容 SQL执行计划的输出可能为多行&#xff0c;每一行代表对一个数据库对象的操作 1. ID列 ID列中的如果数据为一组数字&#xff0c;表示执行SELECT语句的顺…

当当狸AR智能学习图集跨越千年文明传承,邀您“面对面”与虚拟诗人互动对诗

中华传统文化底蕴深厚&#xff0c;余韵悠长。即使经过千年的历史裂变&#xff0c;依然历久铭心慰藉着一代又一代人的灵魂。千百年后的今天&#xff0c;成为了我们独一无二的财富。 如今&#xff0c;国人学习中华传统文化的方式有很多&#xff0c;诗词集、动画影片、诗歌传颂等…

Java,这是一个模仿HashMap的put,get功能的自定义MyHashMap

Java 手写HashMap源码 一&#xff0c;手写源码 这是一个模仿HashMap的put&#xff0c;get功能的自定义的MyHashMap package cn.wxs.demo;import java.io.Serializable; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiFunction; i…

SIM初始化流程

ATR ATR(Answer To Reset)&#xff1a;复位应答信号&#xff0c;有SIM卡传输给终端&#xff0c;包括SIM卡自身的一些信息&#xff0c;比如支持的传输速率&#xff0c;传输模式等。 SIM卡的ATR代表"Answer to Reset"&#xff0c;即复位响应。当SIM卡被插入设备中时…

Linux驱动入门 —— 利用引脚号操作GPIO进行LED点灯

目录 一、字符设备驱动程序框架 编写驱动程序的步骤&#xff1a; 对于 LED 驱动&#xff0c;我们想要什么样的接口&#xff1f; LED 驱动能支持多个板子的基础&#xff1a;分层思想 二、Linux驱动如何指向一个GPIO 直接通过寄存器来操作GPIO 利用引脚号操作GPIO IMX6UL…

算法通关村第十八关-黄金挑战回溯困难问题

大家好我是苏麟 , 今天带来几道回溯比较困难的题 . 回溯有很多比较难的问题&#xff0c;这里我们看两个&#xff0c;整体来说这两个只是处理略复杂&#xff0c;还不是最难的问题 . 大纲 IP问题 IP问题 描述 : 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 …

redis:一、面试题常见分类+缓存穿透的定义、解决方案、布隆过滤器的原理和误判现象、面试回答模板

redis面试题常见分类 缓存穿透 定义 缓存穿透是一种现象&#xff0c;引发这种现象的原因大概率是遭到了恶意攻击。具体就是查询一个一定不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致这个数据的每次请求都需要查DB&#xff0c;数据库压力…

# 和 $ 的区别①

# 和 $ 都是为了获取变量的值 # 和 $ 区别 : 使用 # 查询 id 为 1 的内容 如果看不懂代码,就去看<<Mybatis 的操作(结合上文)续集>>,我这里为了简练一点就不多解释了 Select("select * from userInfo where id #{id}")UserInfo selectOne(Integer id…

Hive命令操作

1.命令行模式 1. 获取帮助 --> hive -H 或-help 2. 运行hive语句 --> hive -e "执行语句" 3. 运行hive文件 --> hive –f "执行文件" 4. 定义变量 --> hive –hivevar keyvalue 5. 引用变量 --> ${varname} 2. 交互模式 1. 进入客户端 -…

【UE 材质】切换颜色、纹理时的过渡效果

效果 步骤 1. 新建一个工程&#xff0c;创建Basic关卡 2. 创建一个材质&#xff0c;这里命名为“M_Plane”&#xff0c;打开这个材质&#xff0c;在材质图表中添加如下节点 注意“Noise”节点中的函数选择“Voronoi” 3. 对材质“M_Plane”创建材质实例 4. 在场景中放置一个平…

【SpringBoot】FreeMarker视图渲染

目录 一、FreeMarker 简介 1.1 什么是FreeMarker&#xff1f; 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…

docker compose部署wordpress

准备机器&#xff1a; 192.168.58.151 &#xff08;关闭防火墙和selinux&#xff09; 安装好docker服务 &#xff08;详细参照&#xff1a;http://t.csdnimg.cn/usG0s 中的国内源安装docker&#xff09; 部署wordpress: 创建目录&#xff1a; [rootdocker ~]# mkdir…

docker-compose容器编排(单机一键拉起所有容器)

1、安装docker-compose实验 安装完成 2、yaml文件 &#xff08;1&#xff09;定义 一种直观的、以竖列形式展示序列化数据格式的标记语言&#xff0c;可读性高。类似于json格式&#xff0c;但语法简单 yaml通过缩进表示数据结构&#xff0c;连续的项目用-减号表示 &#x…

【教程】查看GPU与PCIe版本和匹配速率

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] PCIe理论速度对照表 bash脚本 #!/bin/bash# 查找所有 NVIDIA GPU 设备的设备ID及其类型 device_info$(lspci | grep -i nvidia | egrep "VGA compatible controller|3D controller" | awk {print $1, …

C# WPF上位机开发(动态库dll的开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多时候&#xff0c;我们并不希望所有的程序都放到一个exe里面。因为这样相当于把所有的风险都放在了一个文件里里面&#xff0c;既不利于程序的升…

完全平方数 C语言xdoj49

问题描述 若一个整数n能表示成某个整数m的平方的形式&#xff0c;则称这个数为完全平方数。写一个程序判断输入的整数是不是完全平方数。 输入说明 输入数据为一个整数n&#xff0c;0<n<10000000。 输出说明 如果n是完全平方数&#xff0c;则输出构成这个完全…

Simple Water Caustic Pattern In Unity ShaderGpaph

shadertoy上有各种神奇的效果&#xff0c;以我的见识根本想象不到这些是怎么弄出来的。 不过不会做至少可以先会用。 这篇文章抓取一个shadertoy的示例以制作一个测试效果。 参考这篇shadertoy&#xff0c;使用自定义节点装填hlsl的noise代码 Shader - Shadertoy BETA 首先使…

洛谷P1722 矩阵Ⅱ——卡特兰数

传送门&#xff1a; P1722 矩阵 II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1722 用不需要除任何数的公式来求。 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cmath> #includ…

12.13_黑马数据结构与算法笔记Java

目录 098 堆 heapify 3 099 堆 增删替换 100 堆 e01 堆排序 100 堆e02 求数组第k大元素 100 堆e03 求数据流第k大元素 100 堆e04 求数据流中位数1 100 堆e04 求数据流中位数2 100 堆e04 求数据流中位数3 101 二叉树 概述 102 二叉树 深度优先遍历 103 二叉树 前中后…