蓝桥杯--算法训练 筛选号码

蓝桥杯–算法训练 筛选号码

一.比赛题目

1.题目要求

有n个人围成一圈,顺序排号(编号为1到n)。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子。从下一个人开始继续报数,直到剩下最后一个人,游戏结束。

问最后留下的是原来第几号的那位。
  举个例子,8个人围成一圈:
  1 2 3 4 5 6 7 8
  第1次报数之后,3退出,剩下:
  1 2 4 5 6 7 8 (现在从4开始报数)
  第2次报数之后,6退出,剩下:
  1 2 4 5 7 8 (现在从7开始报数)
  第3次报数之后,1退出,剩下:
  2 4 5 7 8 (现在从2开始报数)
  第4次报数之后,5退出,剩下:
  2 4 7 8 (现在从7开始报数)
  第5次报数之后,2退出,剩下:
  4 7 8 (现在从4开始报数)
  第6次报数之后,8退出,剩下:
  4 7 (现在从4开始报数)
  最后一次报数之后,4退出,剩下:
  7.
  所以,最后留下来的人编号是7。

2.输入与输出

输入:
一个正整数n,(1<n<10000)
输出:
一个正整数,最后留下来的那个人的编号。

输入样例:
8
输出样例:
7

二.分析过程

这道题我觉得用循环链表可能更加轻松简单,链表的删除操作也更加快捷,但是因为我的链表知识不到位,所以我只能用数组来模拟循环链表的操作;

1.整体分析

我们知道他是每数三个数就删掉一个数,被删掉的数字就不会再被数到,所以我们在数数字时需要模拟是否为有效数。
同时需要将有效数和已经被删掉的数字区分开。

2.主要代码分析

while(t<n-1){
		int flag=0;
		while(1)
		{
			if(!a[k%n])
			flag++;
			if(flag==3)
			break;
			k++;
		}
		k=k%n;
		a[k]=1;
		t++;		
	}

在上述代码中,flag代表着筛选这个行为,我们把删掉的数(a[i]就代表着第i个数)赋为1,而删掉之后的数就不会在进行筛选这个行为,所以要加上判断条件if(!a[k%n]

为什么这里是k%n呢?
因为是模拟的循环筛选,所以我们需要始终在n这个范围里面来寻找;

同时最后一个问题:
因为只会剩下一个,所以我们设置一个变量t,每次删掉一个数组之后就t++一次,直到最后数组只剩下一个,退出循环。

三.代码

#include<bits/stdc++.h>
using namespace std;
	//小杨也加入了万能头的行列
#define MAXN 10010
typedef long long ll;
int n,a[MAXN],t=0,k=0;
int main()
{
	scanf("%d",&n);
	memset(a,0,sizeof(a));
	while(t<n-1){
	//从0~n-1筛选(代表1~n个数)
	//数组里面多于一个数没被删除的时候循环筛选
		int flag=0;
		while(1)
		{
			if(!a[k%n])
			flag++;
			if(flag==3)
			break;
			k++;
		}
		k=k%n;
		//每次让k都等于k%n,不然k的数值会越来越大
		a[k]=1;
		//删掉第k+1个数
		t++;		
	}
	for(int i=0;i<n;i++)
	if(a[i]==0)
	{
		printf("%d",i+1);
		break;
	//从第一个数依次向后搜寻,找到那个没被筛选掉的数
	//即其值仍然是0的时候就+1输出,
	//因为我的数组是从0开始的
	//然后退出循环
	}
	return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值