NOIP2017提高组day2 - T2:宝藏

news2024/10/5 13:33:36

题目链接

[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的最小代价为0
    for(int i = 0; i < n; i ++) f[1 << i][0] = 0;
    //状态计算
    for(int state = 1; state < 1 << n; state ++)
    {
        //枚举state的子集s
        for(int s = state - 1 & state; s != 0; s = s - 1 & state)
        {
            //t表示前i-1层的点集状态
            int t = state ^ s, L = 0;
            //枚举第i层所有点,计算第i层的所有点到第i-1层的最小长度之和L
            for(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.coloradmin.cn/o/1308341.html

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

相关文章

Linux 安装图形界面 “startx”

———————————————— 报错&#xff0c;如下&#xff1a; bash :startx command not found ———————————————— 解决方法&#xff1a; 1.先安装 — X Windows System&#xff0c;输入以下命令&#xff1a; yum groupinstall “X Window System”…

IPQ6010 vs IPQ8072 What’s the difference?|802.11AX WiFi6 Solution DR6018 DR8072

IPQ6010 vs IPQ8072 What’s the difference?|802.11AX WiFi6 Solution DR6018 DR8072 IPQ6010 vs IPQ8072: In-Depth Comparison and Selection Guide The rapid evolution of networking technologies has driven continuous innovation in routers and network devices. Am…

鸿蒙(HarmonyOS)北向开发项目编译问题汇总

运行Hello World Hello World 工程可以运行在模拟器中&#xff0c;或者运行在真机设备中。本示例先以选择将 Hello World 工程运行在模拟器中进行说明&#xff0c;如果选择运行在真机设备中&#xff0c;需要先对工程进行签名&#xff0c;然后才能运行在真机设备中。 DevEco S…

Proxmox创建CentOS虚拟机

文章目录 下载ISO安装文件上传创建虚拟机启动虚拟机设置DNS CentOS配置国内安装源备份原有安装源下载更新国内源清理yum缓存制作新配置文件缓存 下载ISO安装文件 下载地址&#xff1a;https://www.xitongzhijia.net/ 也可去官网进行下载 上传 下面介绍直接通过页面上传&…

三、Java运算符

1.运算符和表达式 运算符&#xff1a; ​ 就是对常量或者变量进行操作的符号。 ​ 比如&#xff1a; - * / 表达式&#xff1a; ​ 用运算符把常量或者变量连接起来的&#xff0c;符合Java语法的式子就是表达式。 ​ 比如&#xff1a;a b 这个整体就是表达式。 ​ 而其…

11.仿简道云公式函数实战-逻辑函数-TRUE

1. TRUE函数 TRUE 函数可直接返回逻辑值 true。 2. 函数用法 TRUE() 3. 函数示例 TRUE 函数一般不会作为函数单独使用&#xff0c;可与其他函数一起使用&#xff0c;或作为判断逻辑的结果。如&#xff0c;判断字段值是否为空时&#xff0c;设置公式为IF(ISEMPTY(方案选择)…

2023-12-12 AIGC-AI工具的基本工作原理

摘要: 2023-12-12 AIGC-AI工具的基本工作原理 AI工具的基本工作原理 AI工具的基本工作原理涉及到一系列复杂的技术和算法。这些原理可以根据不同类型的AI工具进行概括&#xff0c;包括机器学习、自然语言处理、图像识别等。以下是一些关键的AI工具及其工作原理的概述&#xff…

基础算法(1):排序(1):选择排序

今天对算法产生了兴趣&#xff0c;开始学习基础算法&#xff0c;比如排序&#xff0c;模拟&#xff0c;贪心&#xff0c;递推等内容&#xff0c;算法是很重要的&#xff0c;它是解决某个问题的特定方法&#xff0c;程序数据结构算法&#xff0c;所以对算法的学习是至关重要的&a…

【知网稳定检索】第三届人文,智慧教育与服务管理国际学术会议(HWESM 2024)

第三届人文&#xff0c;智慧教育与服务管理国际学术会议&#xff08;HWESM 2024&#xff09; 2024 3rd International Conference on Humanities, Wisdom Education and Service Management 第三届人文&#xff0c;智慧教育与服务管理国际学术会议&#xff08;HWESM 2024&…

LangChain学习二:提示-实战(上半部分)

文章目录 上一节内容&#xff1a;LangChain学习一&#xff1a;模型-实战学习目标&#xff1a;提示词及提示词模板的运用学习内容一&#xff1a;什么是提示词&#xff1f;学习内容二&#xff1a;提示词模板2.1 入门2.2 模板格式2.3 验证模板2.4 序列化提示模板2.5 将少量示例传递…

Linux 高级管理,MySQL服务器的构建与维护

实验环境 某公司因业务范围日益扩大&#xff0c;最近订购了一套基于B/S架构的电子商务系统&#xff0c;在正式部署之前&#xff0c;要 求对现有的httpd服务器进行改造&#xff0c;首先需要增加MySQL数据库服务。 需求描述 1. 编译安装MySQL服务器&#xff0c;并添加为mysqld系…

Centos7防火墙及端口开启

1、防火墙 1.1、查看防火墙是否开启 systemctl status firewalld 1.2、开启防火墙 firewall-cmd --list-ports 1.3、重启防火墙 firewall-cmd --reload 2、端口 2.1、查看所有已开启的端口号 firewall-cmd --list-ports 2.2、手动开启端口 启动防火墙后&#xff0c;默认没有开…

Mybatis-Plus源码解析之MybatisPlusAutoConfiguration(二)

group : com.baomidou version:3.5.2.2-SNAPSHOT SpringBoot是自动装配。Spring则可以在配置类上Import(MybatisPlusAutoConfiguration.class) org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageD…

如何想成为嵌入式工程师?(这些东西您必须知道)

嵌入式的发展怎么样&#xff1f; 嵌入式系统领域一直在迅速发展&#xff0c;伴随着物联网、智能设备、汽车电子、医疗设备等应用的不断增加&#xff0c;对嵌入式技术的需求也在不断扩大。因此&#xff0c;嵌入式领域仍然是一个充满机会的领域&#xff0c;为专业人士提供…

AC修炼计划(AtCoder Beginner Contest 332)

传送门&#xff1a;AtCoder Beginner Contest 332 - AtCoder a,b,c都还是很基础了。d题是一个bfs的纯暴力问题。 E - Lucky bag 看看范围&#xff0c;n15&#xff0c;第一个想法是dfs纯暴力&#xff0c;但所有的情况太大&#xff0c;各种决策层出不穷&#xff0c;会t。所以转…

黑马程序员Javaweb重点笔记(五)(2023版)

文章目录 前言事务管理事务进阶AOPAOP基础 前言 我个人有一个学习习惯就是把学过的内容整理出来一份重点笔记&#xff0c;笔记往往只会包括我认为比较重要的部分或者容易忘记的部分&#xff0c;以便于我快速复习&#xff0c;如果有错误欢迎大家批评指正。 另外&#xff1a;本篇…

GetGuru替代方案:4个理由告诉你为什么选择HelpLook

随着知识管理在现代企业中的重要性日益凸显&#xff0c;选择一款高效、稳定的知识库软件成为了关键。然而&#xff0c;市场上的知识库软件众多&#xff0c;如何选择适合自己的产品呢&#xff1f;本文将为你介绍GetGuru的替代方案——HelpLook&#xff0c;并从四个方面为你分析为…

大数据机器学习深度解读决策树算法:技术全解与案例实战

大数据机器学习深度解读决策树算法&#xff1a;技术全解与案例实战 本文深入探讨了机器学习中的决策树算法&#xff0c;从基础概念到高级研究进展&#xff0c;再到实战案例应用&#xff0c;全面解析了决策树的理论及其在现实世界问题中的实际效能。通过技术细节和案例实践&…

学习深度强化学习---第2部分----RL动态规划相关算法

文章目录 2.1节 动态规划简介2.2节 值函数与贝尔曼方程2.3节 策略评估2.4节 策略改进2.5节 最优值函数与最优策略2.6节 值迭代与策略迭代2.7节 动态规划求解最优策略 本部分视频所在地址&#xff1a;深度强化学习的理论与实践 2.1节 动态规划简介 态规划有两种思路&#xff1…

20章节多线程

20.1线程简介 世间有很多工作都是可以同时完成的。例如&#xff0c;人体可以同时进行呼吸、血液循环、思考问题等活用户既可以使用计算机听歌&#xff0c;也可以使用它打印文件。同样&#xff0c;计算机完全可以将多种活动同时进这种思想放在 Java 中被称为并发&#xff0c;而将…