【蓝桥杯】 2018年决赛C/C++B组 #4 调手表 (BFS、模拟)—— 酱懵静

2018决赛真题C/C++B组 调手表

问题描述
小明买了块高端大气上档次的电子手表,他正准备调时间呢。
在M78星云,时间的计量单位和地球上不同,M78星云的一个小时有n分钟。
大家都知道,手表只有一个按钮可以把当前的数加一。在调分钟的时候,如果当前显示的数是0,那么按一下按钮就会变成1,再按一次变成2。如果当前的数是n-1,按一次后会变成0。
作为强迫症患者,小明一定要把手表的时间调对。如果手表上的时间比当前时间多1,则要按n-1次加一按钮才能调回正确时间。
小明想,如果手表可以再添加一个按钮,表示把当前的数加k该多好啊……
他想知道,如果有了这个+k按钮,按照最优策略按键,从任意一个分钟数调到另外任意一个分钟数最多要按多少次。
注意,按+k按钮时,如果加k后数字超过n-1,则会对n取模。
比如,n=10,k=6的时候,假设当前时间是0,连按2次+k按钮,则调为2。

输入格式
一行两个整数n,k,意义如题。

输出格式
一行一个整数表示:按照最优策略按键,从一个时间调到另一个时间最多要按多少次。

样例输入: 5 3
样例输出: 2

样例解释
如果时间正确则按0次。否则要按的次数和操作系列之间的关系如下:
1:+1
2:+1,+1
3:+3
4:+3,+1

数据范围
对于30%的数据0<k<n<=5
对于60%的数据0<k<n<=100
对于100%的数据0<k<n<=100000

资源约定:
峰值内存消耗(含虚拟机)<256M,CPU消耗<1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…”的多余内容。

注意:
main函数需要返回0;
只使用ANSIC/ANSI C++标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中#include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。



---分割线---



思路一:广度优先搜索
可以把这一系列的点视为一个图中的散点,这样你的任务就变成了在一个有限集合内,去求出遍历完这所有点所需要的最小步数,反正点也不多,总会全部进队列的,也总会结束BFS的。
话都到了这个点上,显然是让我们利用广度优先搜索了(寻找最小步骤)
下面直接给出代码:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

const int MAX=100005;
int dp[MAX];
int n,k;

void bfs()
{
	queue<int> q;	
	q.push(0);
	dp[0]=0;
	while(!q.empty())
	{
		int p=q.front();
		q.pop();
		if(dp[(p+1)%n]==-1)			//下一点若未走则记录步数并入队列 
		{
			dp[(p+1)%n]=dp[p]+1;
			q.push((p+1)%n);
		}
		if(dp[(p+k)%n]==-1)		   //下k点若未走则记录步数并入队列 
		{
			dp[(p+k)%n]=dp[p]+1;
			q.push((p+k)%n);
		}
	}
}

int main()
{
	memset(dp,-1,sizeof(dp));	  //包含于cstring中,这里必须全设为-1,不能为0
	cin>>n>>k;
	bfs();
	int ans=dp[0];
	for(int i=1;i<n;i++) ans=ans>dp[i]?ans:dp[i];
	cout<<ans<<endl;
	return 0;
}



---分割线---



思路二:模拟
我们可以去模拟这个调时间的过程,而最后停止的标志,是所有的点都已走过。
这里可以用一个循环去对每一个和当前步数相同的点进行继续加时,这个能够保证你走的每个点都将是在最优策略下走的最小步数(初始点dp[0]当然为0喽,由于在后面需要区别时间点是否全部走过,故你需要初始化所有dp中的点为-1)。
模拟过程中,不用管那些在之后会被覆盖的时间点,反正最后的退出条件是所有点均被访问过,故最终退出时,输出的步数steep即为最大的那个步数,也就是我们所需要的答案。

#include<iostream>
#include<cstring>
using namespace std;
const int MAX=100005;
int main()
{
	int dp[MAX];
	memset(dp,-1,sizeof(dp));
	dp[0]=0;
	int n,k;
	cin>>n>>k;
	int steep=0;
	while(1)
	{
		int i;
		for(i=0;i<n;i++)
			if(dp[i]==steep)
			{
				dp[(i+1)%n]=steep+1;
				dp[(i+k)%n]=steep+1;
			}
		++steep;
		for(i=1;i<n;i++)
			if(dp[i]==-1) break;
		if(i==n) break; 
	}
	//for(int i=0;i<n;i++) cout<<" "<<dp[i];
	//cout<<endl; 
	cout<<steep<<endl;
	return 0;
}

发布了30 篇原创文章 · 获赞 67 · 访问量 3041

猜你喜欢

转载自blog.csdn.net/the_ZED/article/details/100808460
今日推荐