围圈报数
题目描述
n个人站成一圈,从某个人开始数数,每次数到 m 的人就被杀掉,然后下一个人重新开始数,直到最后只剩一个人。现在有一圈人,k个好人站在一起,k个坏人站在一起。从第一个好人开始数数。你要确定一个最小的 m,使得在第一个好人被杀死前,k 个坏人先被杀死。
输入格式
一行一个整数 k。
输出格式
一行一个整数 m。
#include<bits/stdc++.h>
using namespace std;
int flag=1,k,m;
int main()
{
cin>>k;
m=k;
while(flag)
{
m++;
int num=0;//人的编码从0~2k-1,取余会出现为0的情况
for(int i=1;i<=k;i++)
{
num=(num+m-1)%(2*k-i+1);//最大编号为2k-1,需要取2k的余,否则2k-1==0
if(num<k) break;
if(i==k) flag=0;//n个坏人已经全部被杀死
}
}
cout<<m<<endl;
return 0;
}
圆圈中最后剩下的数字
0, 1, …, n-1这n个数字(n>0)排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。
求出这个圆圈里剩下的最后一个数字。
队列模拟
#include<iostream>
#include<queue>
using namespace std;
queue<int> a;
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
a.push(i);
}
int delet=0;
while(delet<n-1)
{
int step=0;
while(step<m-1)
{
int t=a.front();
a.pop();
a.push(t);
step++;
}
a.pop();
delet++;
}
cout<<a.front()-1;
return 0;
}
dp
利用一种倒推的思想,当有一个人的时候,留下的肯定是0号,当有一个人的时候…每多一个人就要多走一次m,所以(f[i-1]+m) 后面就要加一个m
#include<iostream>
using namespace std;
int main()
{
int n,m,f[100001];
cin>>n>>m;
f[1]=0;
for(int i=2;i<=n;i++)
{
f[i]=(f[i-1]+m)%i;
}
cout<<f[n]<<endl;
return 0;
}