首页 > 其他分享 >【图论】【建模】IOI2016 railroad

【图论】【建模】IOI2016 railroad

时间:2023-06-26 19:33:27浏览次数:37  
标签:连边 int 过山车 sum IOI2016 long 建模 railroad 路段

【图论】【建模】IOI2016 railroad

题目描述

Anna 在一个游乐园工作。她负责建造一个新的过山车铁路。她已经设计了影响过山车速度的 \(n\) 个特殊的路段(方便起见标记为 \(0\) 到 \(n-1\))。现在 Anna 必须要把这些特殊的路段放在一起并提出一个过山车的最后设计。为了简化问题,你可以假设过山车的长度为零。

对于 \(0\) 和 \(n-1\) 之间的每个 \(i\),这个特殊的路段 \(i\) 具有如下两个性质:

  • 当进入这个路段时,有一个速度限制:过山车的速度必须小于或等于 \(s_i\) \(\text{km/h}\)(每小时千米)。

  • 当离开这个路段时,过山车的速度刚好是 \(t_i\) \(\text{km/h}\),不管过山车进入该路段时的速度如何。

最后完成的过山车设计是一个以某种顺序包含这 \(n\) 个特殊路段的单一铁路线。这 \(n\) 个路段中的每一个应当被使用刚好一次。连续的路段之前用铁轨来连接。Anna 应该选择这 \(n\) 个路段的顺序,然后确定每段铁轨的长度。铁轨的长度以米来衡量,可以是任意的非负整数(可以为零)。

两个特殊路段之间的每 \(1\) 米铁轨可以将过山车的速度减慢 \(1\) \(\text{km/h}\)。在这个过山车铁路的起点,过山车按照 Anna 选择的顺序进入第一个特殊路段时的速度是 \(1\) \(\text{km/h}\)。

最后的设计还必须满足以下要求:

  • 过山车在进入这些特殊路段时不能违反任一个速度限制。

  • 过山车的速度在任意时刻为正。

你的任务是找出这些路段之间铁轨的最小可能总长度(这些路段之间铁轨总长度的最小值)。

算法描述

嘿嘿,这是个图论题

翻译题面:有\(n\)个轨道,进入速度恰好为\(s_{i}\),出速度为\(t_i\),降速\(x\)花费代价\(x\),提速无代价,求轨道的最小排列。

解释下为什么可以看作\(s_i\),观察原题面,我们将相邻元素分为两种情况:

  1. \(t_i > s_{i + 1}\) : 由于从\(i + 1\)出去时值一定是\(t_{i + 1}\),所以最短一定最优,将速度(原题面)刚好降到\(s_{i + 1}\)。

  2. \(t_i \leq s_{i + 1}\) : 不用降速,耗费为0,加速耗费也为0,可以看作加到了\(s_{i + 1}\)

如果将一个数带进这个排列模拟其变化(即原题的坐过山车),我们发现,对于每一个\(s_i、t_i\),一定有一个时刻的速度等于它,并且由一个“\(inf\)”状态进入\(t_1\),且从最后一个\(s_n\)回到这个"\(inf\)"状态。也就是说,如果我们把包含\(inf\)在内的每一种速度看作一个节点,那么一趟过山车一定会经过每一个节点(可能不止一次)。

所以我们将速度离散化。试图将它转化成边的问题,我们对于每一条轨道,将\(s_i\)向\(t_i\)连一条有向边,长度为0,代表花费0代价就可以经过这条轨道,我们发现这条边在从\(inf\)出发到\(inf\)的路径中是必走的边,这启发我们构造一个最短欧拉回路,让每条边必经过一次,边权和就是答案。一开始这些点都是不相通的,所以用一个并查集维护点的连通性。

首先将\(s_i\)到\(t_i\)之间的边连好,再连\(max\{s_i,t_i\}\)到\(inf\)的边和\(inf\)到\(1\)的边(边权是0所以不用计入答案)。接着我们要将添加权值最小的边使得其成为一个欧拉回路,我们对于\(i \in \{S,T\}\),将\(i\)向\(i + 1\)连边。我们发现跨过很多个点连边的代价和与相邻点连边代价之和是一样的,所以每个点都只和相邻的点连边,并且对于每个点,对于覆盖这个点的一些边,向左和向右的数量应该是一样的,所以先前添加\(s_i\to t_i\)的时候,在离散化数组中将\(s_i\)加1,\(t_i\)减一,然后做一遍前缀和,可以发现,\(sum_i > 0\)代表向右的边更多,\(|sum_i|\)就是多出来的个数,所以我们从\(i + 1\)到\(i\)连\(|sum_i|\)条边,每条边权为\(v_{i + 1} - v_i\)(\(v\)是离散化数组)。由于这些边是为了构造欧拉回路而生的,所以必须连,直接将边权加进答案,后文同理。

(记得连边时并查集上合并两端点)

这时检查答案,发现我们事实上将这个图连成了若干子欧拉回路,要合并这些回路,就要在它们之间建一条双向边,其中提速边为0,降速边为\(|v_u -v_v|\)。同上文,在相邻两点之间连边一定是最优的,所以直接遍历一遍节点,如果\(i\)和\(i + 1\)在并查集中不连通,就在它们之间加一条边权为\(v_{i + 1} - v_i\)的边,因为节点间的连通性不规律,所以这样相邻连边最后连下来是一个图,将这些新加的边跑一次最小生成树即可,树边计入答案。

不愧是IOI题目

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5,inf = 1e9 + 7;
struct Edge{
	int u,v;long long w;
}e[N * 4];
long long n,m,s[N],t[N],v[N * 4],sum[N * 4],cnt = 0,tot = 0;
long long ans = 0;
inline int sch(long long x)
{
	int l = 1,r = cnt;
	while(l < r)
	{
		int mid = (l + r) >> 1;
		if(x <= v[mid]) r = mid;
		else l = mid + 1;
	}
	return l;
}
struct UFS{
	int fa[N * 4];
	inline void init()
	{
		for(int i = 1;i <= cnt;i++) fa[i] = i;
	}
	inline int find(int x)
	{
		if(fa[x] == x) return x;
		return fa[x] = find(fa[x]);
	}
	inline void unionn(int x,int y)
	{
		x = find(x);y = find(y);
		fa[x] = y;
	}
}p;
inline void add(int x,int y,int z)
{
	++tot;
	e[tot].u = x;
	e[tot].v = y;
	e[tot].w = z;
}
inline bool cmp(Edge x,Edge y)
{
	return x.w < y.w;
}
signed main()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++)
	{
		cin>>s[i]>>t[i];
		v[++cnt] = s[i]; v[++cnt] = t[i];
	}
	s[++n] = inf; t[++n] = 1; v[++cnt] = s[n];v[++cnt] = t[n];
	sort(v + 1,v + cnt + 1);
	cnt = unique(v + 1,v + cnt + 1) - (v + 1);
	p.init();
	for(int i = 1;i <= n;i++)
	{
		s[i] = sch(s[i]);
		t[i] = sch(t[i]);
		++sum[s[i]];--sum[t[i]];
		p.unionn(s[i],t[i]);
	}
	for(int i = 1;i <= cnt - 1;i++)
	{
		sum[i] += sum[i - 1];
		if(sum[i] > 0) ans += sum[i] * (v[i + 1] - v[i]);
		if(sum[i]) p.unionn(i + 1,i);//i -> i + 1 or i + 1 -> i都要连边、连通块相同 
	}
	for(int i = 1;i <= cnt - 1;i++)
		if(p.find(i) != p.find(i + 1))
			add(p.find(i),p.find(i + 1),v[i + 1] - v[i]);
	sort(e + 1,e + tot + 1,cmp);
	for(int i = 1;i <= tot;i++)
	{
		if(p.find(e[i].u) == p.find(e[i].v)) continue;
		p.unionn(e[i].u,e[i].v);
		ans += e[i].w;
	}
	cout<<ans;
	return 0;
}

代码小细节:在这一段当中

for(int i = 1;i <= cnt - 1;i++)
{
	sum[i] += sum[i - 1];
	if(sum[i] > 0) ans += sum[i] * (v[i + 1] - v[i]);
	if(sum[i]) p.unionn(i + 1,i);//i -> i + 1 or i + 1 -> i都要连边、连通块相同 
}

\(sum_i > 0\)和\(sum_i\)两个条件是不一样的,因为\(if(sum_i)\)指的是\(sum_i\)只要不为零,无论正负都为\(true\),这里的意思就是无论向左还是向右连边,\(i\)和\(i + 1\)都要联通。然而前面的一句就是只在向右连边的时候将边权计入答案,向左连时就是0。

标签:连边,int,过山车,sum,IOI2016,long,建模,railroad,路段
From: https://www.cnblogs.com/TheLastCandy/p/17506550.html

相关文章

  • 整车动力学模型_simulink(7自由度&14自由度) 采用模块化建模方法,搭建7自由度和14自由度
    整车动力学模型_simulink(7自由度&14自由度)原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/644996670327.html软件使用:MatlabSimulink适用场景:采用模块化建模方法,搭建7自由度和14自由度整车模型,作为整车平台适用于多种工况场景。产品simulink源码包含如下模块:→工况:阶跃......
  • 系统架构设计师笔记第22期:软件可靠性建模
    软件可靠性建模是指通过分析软件系统的特征和行为,预测其可能出现的故障和失效情况,从而评估软件系统的可靠性和安全性。软件可靠性建模通常使用统计方法和数学模型,以定量分析软件系统的可靠性和安全性。以下是一些常见的软件可靠性建模方法:故障树分析(FTA):FTA是一种演绎推理方法,通过识......
  • 肖桐、朱靖波-机器翻译统计建模与深度学习方法
        分享一本由肖桐、朱靖波老师编著,东北大学自然语言处理实验室·小牛翻译 联合出品的新书《机器翻译统计建模与深度学习方法》。本书中文编著,对机器学习相关历史和涉及知识进行详细、全面、深入讲解,非常值得深入阅读、学习。          本书全面回顾了近三十年内......
  • 统计建模与回归分析
    目录1.引言2.技术原理及概念3.实现步骤与流程4.应用示例与代码实现讲解5.优化与改进统计建模与回归分析是机器学习领域的重要分支,用于建立预测模型,以预测某种变量值。这种预测模型通常基于一系列统计学假设和数学方程,以实现对数据的预测。在这篇文章中,我们将介绍统计建模与......
  • 直接电流双闭环控制方式的pwm整流器仿真,带建模计算技术文档simulink仿真,电流内环采用
    直接电流双闭环控制方式的pwm整流器仿真,带建模计算技术文档simulink仿真,电流内环采用滞环控制电压外环为pi控制授人之鱼,不如授人之渔带pwm整流的传递函数推导,PID参数,硬件参数计算文档。所带资料还包含一个传递函数的仿真。ID:5349595753777152......
  • 精通C语言中的函数:创建模块化代码
    在C语言中,函数是一种非常重要的概念,它允许我们将代码划分为模块化的部分,提高代码的可读性和可维护性。函数还可以被多次调用,避免代码的冗余。本文将探索C语言中的函数,并提供相关的代码示例,帮助你更好地理解和应用函数的概念。函数的定义和调用在C语言中,函数由函数头和函数体组成。......
  • Matlab的simulink控制框图助攻教程 Simulink建模框图
    Matlab的simulink控制框图助攻教程Simulink建模框图搭建参数设置调整数据分析等等手把手教学,并输出说明文档。安装软件以及LMS.Virtuallab动力学仿真软件AMESIM动力学仿真软件安装使用教程全包。本教程提供了一种使用Matlab的Simulink控制框图进行辅助教学的方法。通过S......
  • SolidWorks软件三维建模教程——莫比乌斯环建模案例
    SolidWorks是达索系统(DassaultSystemes)下的子公司,专门负责研发与销售机械设计软件的视窗产品。SOLIDWORKS软件三维建模功能强大,为制造型企业提供SOLIDWORKS一体化解决方案和服务。今天微辰三维就以莫比乌斯环的三维建模案例,为您提供详细的SolidWorks软件三维建模教程。一起来看如......
  • 使用PyMC进行时间序列分层建模
    在统计建模领域,理解总体趋势的同时解释群体差异的一个强大方法是分层(或多层)建模。这种方法允许参数随组而变化,并捕获组内和组间的变化。在时间序列数据中,这些特定于组的参数可以表示不同组随时间的不同模式。今天,我们将深入探讨如何使用PyMC(用于概率编程的Python库)构建分层时......
  • Blender建模
    目标:建树先建一个面然后添加一个修改器,蒙皮修改器 再添加一个修改器,表面细分,  这时候选中物体,按e键即可添加树干或者树枝,Ctrl+A可以添加缩放。这是我建立的模型效果: ......