标题:调手表
小明买了块高端大气上档次的电子手表,他正准备调时间呢。
在 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;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include <xxx>
不能通过工程设置而省略常用头文件。
提交程序时,注意选择所期望的语言类型和编译器类型。
dp显然可以,还是简单的完全背包,虽然像是价值确定,求最小质量,不过没关系,该怎么写还是怎么写;
我以为用数论也可以,毕竟就是公倍数公约数那点事;
公约数公倍数:学过数论了不起啊;
我:是啊,学过数论就是了不起啊。不过我没学过。
那种我也懒得写了,万一有时间再说吧,没时间就鸽了;
年轻人,要不要学bfs,效果也不错哦,一发AC的那种啊 (其实就类似数论的,不过只是完整模拟一遍,不用脑子的,还是把
数论鸽了吧);
DP
1)类完全背包:(我这个dp[x]表示+x的最少操作数)
#include"iostream"
#include"cstring"
#define INF 100000
using namespace std;
int a[5],N,K,dp[100001];
int main(){
cin >> N >> K;
a[0] = 1;a[1] = K;
memset(dp,INF,sizeof(dp));
dp[0] = 0;
int Max = 0;
for(int j = 1;j <= N;j++)
for(int i = 0;i < 2;i++)
if(dp[j]>=a[i])
dp[j] = min(dp[j-a[i]]+1,dp[j]);
else
dp[j] = dp[j-1]+1;
for(int i = 0;i < N;i++)
if(Max<dp[i])Max = dp[i];
cout << Max;
return 0;
}
2)大佬说ta是伪dp,还收敛不收敛的,让我一个高数不太好的人难受,有缘人自己看看吧 。
我这个思路呢,怎么说呢,假的dp吧,我用了一个状态转移方式dp[i] = min(dp[(i + n – k) % n] + 1, dp[i – 1] + 1),就是要么从上一步走一步过来,要么从上k步走一步过来。因为他们的值是相关联的,所以每改一个值都要进行更新其他值,所以用了一个while(1),直到过程收敛,我用了一个sum来判断是不是收敛了,因为dp[i]要么减小,要么不变,所以当他们的和不变了,即收敛了,输出结果即可了。
#include<bits/stdc++.h> using namespace std; int dp[100005]; int main(){ int n, k; cin>>n>>k; for(int i = 0; i < n; i++) dp[i] = i; // 初始化为多少分钟就要调多少次,默认一次调一分钟 for(int i = k; i < n; i += k) //从0出发,每+k步数就加一次 dp[i] = dp[i - k] + 1; for(int i = k + 1; i < n; i += k) // 从1出发,每+k步数就加一次 dp[i] = dp[i - k] + 1; int sum = -1; while(1){ // 如果结果收敛,则停止循环,这里我们算他们的和,如果他们的步数和不变了,说明收敛了 int now_sum = 0; for(int i = 2; i < n; i++){ now_sum += dp[i]; dp[i] = min(dp[(i + n - k) % n] + 1, dp[i - 1] + 1);// 每一步都可以由上一步调k步或者1步得到 } if(now_sum == sum) break; sum = now_sum; } int maxdp = dp[0]; for(int i = 0; i < n; i++){ // cout<<dp[i]<<" "; maxdp = max(dp[i], maxdp); } cout<<maxdp<<endl; return 0; }
———————
作者:Au-csdn
来源:CSDN
原文:https://blog.csdn.net/hzj1998/article/details/80492044
版权声明:本文为博主原创文章,转载请附上博文链接!
BFS
bfs吗,哇嘎哒。懒得写,还是看同一个大佬怎么说吧。
你可能会有疑问,为什么还是这个大佬。因为大佬就这么多,可能你这么努力,甚至别人在玩的时候还在看博客,但你成为大佬的几率还是很小,值得吗,还应该努力吗?答案是:努力,努力,再努力。直到真正变强的那天,请你务必给我点个关注,那我就有大佬关注了,嘻嘻。
再来另一种解法吧,广度搜索(bfs)解决的,因为广度搜索出来的步数一定是最小的。思路是从0出发,每次走1步或k步,一直这样,用一个vis[i]判断i是否走过。一直这样,直到走完所有点。
#include<bits/stdc++.h> using namespace std; queue<int> que; int step[100005]; bool vis[100005]; int main(){ int n, k; cin>>n>>k; for(int i = 0; i < n; i++){ step[i] = 0; vis[i] = false; } que.push(0); step[0] = 0; vis[0] = true; while(!que.empty()){ int now = que.front(); que.pop(); int one_step = (now + 1) % n; if(vis[one_step] == false){ vis[one_step] = true; step[one_step] = step[now] + 1; que.push(one_step); } int k_step = (now + k) % n; if(vis[k_step] == false){ vis[k_step] = true; step[k_step] = step[now] + 1; que.push(k_step); } } int max_step = step[0]; for(int i = 0; i < n; i++) max_step = max(max_step, step[i]); cout<<max_step<<endl; return 0; }
———————
作者:Au-csdn
来源:CSDN
原文:https://blog.csdn.net/hzj1998/article/details/80492044
版权声明:本文为博主原创文章,转载请附上博文链接!
今天的文章2018蓝桥杯比赛时间_第九届蓝桥杯[通俗易懂]分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/59137.html