最小化蒙德城的旅行者队伍(巴士)

2024-05-08 03:52

本文主要是介绍最小化蒙德城的旅行者队伍(巴士),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

描述

在阳光明媚的一天,凯亚在蒙德城的风车塔下等待着前往狼的领域的旅行者。他于12:00抵达,并计划在此地逗留一整小时,直至12:59。

蒙德城有许多旅行者的车队,每个车队都有自己的出发时间表。

凯亚观察了这些车队的出发时间,并记录了以下发现:

  1. 在12:00至12:59期间,同一车队的旅行者会以相同的时间间隔到达风车塔。
  2. 每个车队至少有两名旅行者在这一时间段到达。
  3. 不同车队的旅行者可以同时到达风车塔。
  4. 不同车队的旅行者首次到达风车塔的时间和到达的时间间隔都有可能相同。
  5. 测试用例中的车队总数不会超过17个。

请你帮助凯亚编写一个程序,求出在所有旅行者到达风车塔的时刻满足输入数据的要求的情况下,车队的总数量最小是多少。

输入

输入数据第一行包含整数 n,表示在这一小时内抵达到风车塔的旅行者总数量。

第二行包含 n 个整数,表示按升序排序得到的 n 个旅行者的到达时间。

1≤n≤300

输出

输出一个整数,表示最小车队数。

输入样例 1 
17
0 3 5 13 13 15 21 26 27 29 37 39 39 45 51 52 53

输出样例:

3

思路:

最开始我想得是枚举所有的起点然后开始深搜,但是发现这样时间复杂度太高了,所以参考了y总的代码。

先预处理出所有可能的路线:先枚举起点 i,再枚举公差 j。

由于i是起点,因此0 ~ i - 1中不能包含任何该序列的点,所以公差j至少是i + 1;
由于0 ~ 59之间至少要包含两个点,因此i + j一定小于60;

剩下的问题变成:最少从合法线路中选出多少条,才可以覆盖所有给定的公交车。

剪枝:

①由于是枚举组合数,并不是排列数,为了避免重复在DFS时传入当前枚举的起点。
②将所有等差数列按长度排序,优先枚举长度较长的等差数列。这样在搜索树中前几层的分支少,可以更快地发现矛盾然后回溯。
③由于剪枝2的存在,当前路线覆盖的点数是最多的,如果当前路线能覆盖的点数 * 剩余可选的路径条数 + 当前已经覆盖的点数 < 总点数,说明当前方案一定非法,直接回溯即可。

代码实现

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int M=60;
int n;
int time[M];//用于记录时间t到达的旅行者的个数
//存储该路径旅行者的个数、起点、差值
vector<pair<int,PII>> routes;bool is_route(int a,int d)
{//判断是否为可行解for(int i=a;i<60;i+=d)if(!time[i])return false;return true;
}
bool dfs(int depth,int u,int sum,int start)
{//sum记录当前已经安排的旅行者人数if(u==depth)return sum==n;//限界函数if(routes[start].first*(depth-u)+sum<n)return false;for(int i=start;i<routes.size();i++){auto r=routes[i];int a=r.second.first,d=r.second.second;//约束函数if(!is_route(a,d))continue;//由于枚举过程中time数组会改变所以要再次判断for(int j=a;j<60;j+=d)time[j]--;if(dfs(depth,u+1,sum+r.first,i))return true;for(int j=a;j<60;j+=d)time[j]++;//恢复现场}return false;
}
int main()
{scanf("%d",&n);for(int i=0;i<n;i++){int t;scanf("%d",&t);time[t]++;}//预处理出所有的可能线路for(int i=0;i<60;i++){//枚举起点和差值for(int j=i+1;i+j<60;j++)if(is_route(i,j))routes.push_back({(59-i)/j+1,{i,j}});}//优先枚举长度较长的等差序列,前几层的分支少sort(routes.begin(),routes.end(),greater<pair<int,PII>>());int depth=0;while(!dfs(depth,0,0,0))depth++;printf("%d\n",depth);return 0;
}

这篇关于最小化蒙德城的旅行者队伍(巴士)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/969237

相关文章

【C++二分查找】2439. 最小化数组中的最大值

本文涉及的基础知识点 C++二分查找 LeetCode2439. 最小化数组中的最大值 给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。 每一步操作中,你需要: 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0 。 将 nums[i] 减 1 。 将 nums[i - 1] 加 1 。 你可以对数组执行 任意 次上述操作,请你返回可以得到的 n

RDP最小化之后仍然保持UI渲染的方法

RDP最小化之后仍然保持UI渲染的方法 1、运行regedit 2、找到注册表项HKEY_CURRENT_USER\Software\Microsoft\TerminalServer Client 3、新建一个类型为DWORD的注册表项RemoteDesktop_SuppressWhenMinimized并设置值为2 4、然后找到注册表项HKEY_CURRENT_USER\Soft

Electron基础(一) 实现最大化、最小化、关闭窗口功能

在 Electron 中,默认情况下,如果你没有隐藏或自定义窗口的标题栏,那么窗口的最小化和关闭按钮通常是自动提供的。但是,当你通过 frame: false 选项隐藏了默认的窗口边框和标题栏时,你需要自己实现这些功能。  1.主进程文件中定义事件 如果你不知道哪个是主进程文件,看下package.json中main对应的配置 "main": "public/electron.js"

POJ3273-Monthly Expense (最小化最大值)

题目链接:click here~~ 【题目大意】  农夫JF在n天中每天的花费,要求把这n天分作m组,每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值 【解题思路】: 经典的最小化最大值问题,要求连续的m个子序列,子序列的和最大值的最小,枚举满足条件的m的最小值即为答案,因此二分查找。 1.是否能把序列划分为每个序列之和不大于mid的m个子序列

UVA10048 - Audiophobia(Floyd,最大值的最小化)

UVA10048 - Audiophobia(Floyd,最大值的最小化) UVA10048 - Audiophobia 题目大意:给定一无向图,每条边都有一个权值,现在给你起点和终点,要求你找出起点到终点途经的边的最大值,要求这个值尽量小,到不了输出no path。 解题思路:在floyd过程中,就可以记录下来。G【i】【j】 = min(G【i】【j】, max(G【i】【k】, G

outlook最小化到托盘设置/如何设置outlook点关闭是保留在系统托盘

1需求 outlook最小化到托盘设置/如何设置outlook点关闭是保留在系统托盘/实现关闭outlook 自动最小化到系统托盘 最小化的时候, 它就会自己缩到托盘区. 2解决办法 2.1 中文版 在打开outlook的时候在托盘区右击点“最小化时隐藏”,也可以起到同样效果,简单易行。 2.2 英文版 在打开outlook的时候在托盘区右击点“Hide When Minimized

改进rust代码的35种具体方法-类型(二十二)-最小化可见度

上一篇文章 改进rust代码的35种具体方法-类型(二十一)-熟悉Cargo.toml版本使用 Rust允许将代码元素隐藏或暴露给代码库的其他部分。本项目探讨了为此提供的机制,并就应在何时何地使用它们提出建议。 可见性语法 Rust的基本可见性单位是模块。默认情况下,模块的项目(类型、方法、常量)是私有的,只能访问同一模块及其子模块中的代码。 需要更广泛可用的代码用pub关键字标记

双循环比赛队伍排列组合问题

2019/05/12 引言 昨天看比赛的时候,看到了各个队伍的对战,这种应用应该是排列组合中的算法,但不是很明确。搜索了一下相关的算法,看到有用分治法的。这里来把这部分的问题来描述一下。 问题分析 问题来源于最近的MSI比赛: 小组赛共计6支队伍,按照双循环赛事,共计比赛5天,每天打6场,每个队每天打2场,第3天的上半轮(即前三场)完成第一轮循环赛,共计30场比赛。 转化为数学形

MFC获取窗口最大化/最小化信息

方法1:在WM_SYSCOMMAND的响应函数中处理: afx_msg void OnSysCommand( UINT nID, LPARAM lParam ); 判断第一个参数: SC_MAXIMIZE (or SC_ZOOM)   Maximize the CWnd object. SC_MINIMIZE (or SC_ICON)   Minimize the CWnd object

1204. 最后一个能进入巴士的人

1204. 最后一个能进入巴士的人 题目链接:1204. 最后一个能进入巴士的人 代码如下: # Write your MySQL query statement belowselect a.person_namefrom Queue as a,Queue as bwhere a.turn>=b.turngroup by a.person_id having sum(b.weig