洛谷 P1145:[CERC 1995] 约瑟夫 ← 队列 + 优化
【题目来源】
https://www.luogu.com.cn/problem/P1145
【题目描述】
2k 个人站成一圈,从某个人开始数数,每次数到 m 的人就被杀掉,然后下一个人重新开始数,直到最后只剩一个人。现在有一圈人,k 个好人站在一起,k 个坏人站在一起。从第一个好人开始数数。你要确定一个最小的 m,使得在 k 个坏人均被杀死时 k 个好人都存活。
【输入格式】
一行一个整数 k。
【输出格式】
一行一个整数 m。
【输入样例一】
3
【输出样例一】
5
【输入样例二】
4
【输出样例二】
30
【数据范围】
0<k<14。
【算法分析】
● 注意题目中的关键陈述“k 个好人站在一起,k 个坏人站在一起。从第一个好人开始数数”,这个代码会直接体现。
● 由于所有人始终围成一圈进行报数,当报数次数恰好等于当前队列总人数时,相当于绕圈一周后回到起点。因此在如下代码中模拟报数过程时,不必真的执行完整的 m-1 次移动操作,只需通过取模运算 (m-1) % len 计算出有效偏移步数,直接跳过所有绕圈的冗余操作。这一优化能将原本可能高达数万次的循环骤减为最多几十次,大幅降低时间开销,从而避免程序超时。--- 这就是这道题必须加、不加必超时(TLE)的优化策略!
【算法代码】
#include <bits/stdc++.h>
using namespace std;
bool check(int k,int m) {
queue<int> q;
//First good k people, then bad.
for(int i=1; i<=2*k; i++) q.push(i);
for(int i=1; i<=k; i++) { //Kill k bad.
int len=q.size();
int step=(m-1)%len;
for(int j=0; j<step; j++) {
q.push(q.front());
q.pop();
}
//Dequeue the mth element
int t=q.front();
q.pop();
//If killed good, failure.
if(t<=k) return false;
}
return true;
}
int main() {
int k,m=1;
cin>>k;
while(true) {
if(check(k,m)) {
cout<<m<<endl;
break;
}
m++;
}
return 0;
}
/*
in:3
out:5
*/
【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/149135096
https://blog.csdn.net/hnjzsyjyj/article/details/108410252
https://blog.csdn.net/hnjzsyjyj/article/details/127023239
https://blog.csdn.net/hnjzsyjyj/article/details/133636109

浙公网安备 33010602011771号