C++经典题目:有n个人围成一圈,顺序排号,然后数数进行淘汰的解法和一些思考
问题描述:
有n个人围成一圈,顺序排号。从第一个人开始报数(1~3报数),凡报到3的人退出圈子,问最后留下的人原来排在第几号。
分析:
首先由用户输入人数n,然后对这n个人进行编号【因为如果不编号的话,我们就不能知道最后是哪位童鞋留下来了:)】
然后就开始了一圈一圈的循环,不断形成新的圈子,不断有人被淘汰,那么循环到什么时候截止呢?对只剩最后一个人,也就是说淘汰n-1了个人的时候,这个时候停止循环。
在实际情况中,应该是这n个人一开始围成了一个大圈子,然后随着不断的淘汰,圈子不断减小,最后剩下的那个人的一开始的编号就是我们要的结果。
我在用数组来表示这些人,因为进行了初始化,所以数组中元素的值都是原来的编号,因此我们只需要将被淘汰的人对应的数组元素的值设置为0即可。然后随着不断的循环,最后只剩下一个值不为0的数组元素,这个元素就是我们要的结果。
程序代码:
#include<iostream>
#define MAXNUM 100
using namespace std;
int main()
{
int a[MAXNUM];
int n=0; //n表示一共多少人
int m=0; //m表示被淘汰的人数
int i=1; //每轮循环中的计数器
int k=0; //用来表示报数的数
int j=0; //用于循环的计数器
cout<<"请输入总人数:";
cin>>n;
//对数据进行初始化操作,给每个人进行编号
for(j=1;j<=n;j++)
{
a[j]=j;
}
//通过循环不断淘汰人,直到最后只剩下一个人
while(m < n-1)
{
if(a[i]!=0) //判断该人是否已经淘汰
{
k++;
}
if(k == 3)
{
a[i]=0; //淘汰报数为3的人(即将其值设置为0)
k=0; //将k置为0,重新报数
m++; //对淘汰人数进行计数
}
i++; //对下一个人进行判断
if(i == n+1) //到了圈子的末尾出处,下一个位置将是圈子的开始
{
i=1; //将下一个人置为 1(圈子的开始位置 )
}
}
for(j=1;j<=n;j++)
{
if(a[j]!=0)
{
cout<<"\n最后剩下的人原来的编号为:"<<a[j]<<" 的人\n"<<endl;
}
}
return 0;
}
运行界面:
延伸思考:
将用于淘汰的数字设置为变量:
上面的题目中人数n是一个变量,但是数到3就淘汰,这个数组是确定的,我们想要这个用于淘汰的数组t也作为变量,要怎么修改呢?
其实不用太大的修改,只需要设置一个变量,并由用户输入数据完成初始化,然后用来作为淘汰的数字,程序代码如下:
#include<iostream>
#define MAXNUM 100
using namespace std;
int main()
{
int a[MAXNUM];
int n=0; //n表示一共多少人
int m=0; //m表示被淘汰的人数
int i=1; //每轮循环中的计数器
int k=0; //用来表示报数的数
int j=0; //用于循环的计数器
int t=0; //用于淘汰的数字变量
cout<<"请输入总人数n:";
cin>>n;
cout<<"请输入用于淘汰的数字t:";
cin>>t;
//对数据进行初始化操作,给每个人进行编号
for(j=1;j<=n;j++)
{
a[j]=j;
}
//通过循环不断淘汰人,直到最后只剩下一个人
while(m < n-1)
{
if(a[i]!=0) //判断该人是否已经淘汰
{
k++;
}
if(k == t)
{
a[i]=0; //淘汰报数为3的人(即将其值设置为0)
k=0; //将k置为0,重新报数
m++; //对淘汰人数进行计数
}
i++; //对下一个人进行判断
if(i == n+1) //到了圈子的末尾出,下一个位置将是圈子的开始
{
i=1; //将下一个人置为 1(圈子的开始位置 )
}
}
for(j=1;j<=n;j++)
{
if(a[j]!=0)
{
cout<<"\n最后剩下的人原来的编号为:"<<a[j]<<" 的人\n"<<endl;
}
}
return 0;
}
程序运行界面:
使用单链表解决该问题
这个问题中的n虽然看起来是变量,但是我们通过代码可以看出来,它其实是有一个上线MAXNUM的,也就是当用户输入的n大于MAXNUM的时候就会出错。
那么,我们应如何写出真正意义上的可以让用户输入一个不受到限制的变量呢(实际上无论如何都收到数据类类型长度的限制的=.=)?
并且,当n很大的时候,我们就需要在内存中开辟一块连续的内存空间,在内存比较小的时候,这样做有可能无法分配内存,而单链表即满足了逻辑上的连续,而物理上却可以是不连续的。
(关于C++中的单链表,如果不是很明白可以看看这篇文章:C++中单链表的建立和操作)
示例代码如下:
#include<iostream>
using namespace std;
struct Node
{
int num;
Node *next;
};
Node * Add(Node *head,int i)
{
Node *node,*htemp;
if(!(node = new Node))
{
cout<<"分配内存失败!"<<endl; //分配内存失败
return NULL;
}
else
{
node->num=i; //保存结点数据
node->next = NULL; //设置结点指针为空,即作为表尾
if(head == NULL) //当链表是空表的时候
{
head = node;
return head;
}
htemp = head;
while(htemp->next != NULL) //查找链表的末尾
{
htemp = htemp->next;
}
htemp->next = node;
return head;
} }
Node *FindNodeNum(Node *head,int k)
{
Node *htemp;
int i = 1;
htemp = head; //保存链表头指针
for(i = 1;i<k&&htemp;i++) //找到该结点
{
htemp = htemp->next;
}
return htemp; //返回指向第k个结点的指针
}
int main()
{
int n=0; //n表示一共多少人
int m=0; //m表示被淘汰的人数
int i=1; //每轮循环中的计数器
int k=0; //用来表示报数的数
int j=0; //用于循环的计数器
int t=0; //用于淘汰的数字变量
cout<<"请输入总人数n:";
cin>>n;
cout<<"请输入用于淘汰的数字t:";
cin>>t;
//对数据进行初始化操作,给每个人进行编号
Node *head=NULL;
for(j=1;j<=n;j++)
{
head=Add(head,j);
}
Node *nodeData;
//通过循环不断淘汰人,直到最后只剩下一个人
while(m < n-1)
{
nodeData=FindNodeNum(head,i);
if(nodeData->num!=0) //判断该人是否已经淘汰
{
k++;
}
if(k == t)
{
nodeData->num=0; //淘汰报数为3的人(即将其值设置为0)
k=0; //将k置为0,重新报数
m++; //对淘汰人数进行计数
}
i++; //对下一个人进行判断
if(i == n+1) //到了圈子的末尾出,下一个位置将是圈子的开始
{
i=1; //将下一个人置为 1(圈子的开始位置 )
}
}
for(j=1;j<=n;j++)
{
nodeData=FindNodeNum(head,j);
if(nodeData->num!=0)
{
cout<<"\n最后剩下的人原来的编号为:"<<nodeData->num<<" 的人\n"<<endl;
}
}
return 0;
}
运行界面:
C++经典题目:有n个人围成一圈,顺序排号,然后数数进行淘汰的解法和一些思考的更多相关文章
- 【转】约瑟夫环算法---------题目:有n个人围成一圈,顺序排号,从第一个开始报数(从1到3报数),凡报到3的人退出圈子,问最后最后留下的是原来第几号的那位.
提示:用环形链表实现 对于这个题目其实就是用c语言的循环链表实现一个约瑟夫环.我们可以定义一个循环链表,将这n个人加入到链表中,然后定义三个节点指针在链表上循环,移动跨度为3,利用链表的循环功能每次删 ...
- 37 有n个人围成一圈,顺序排号,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号那位.
题目:有n个人围成一圈,顺序排号,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号那位. public class _037NumberOff { public st ...
- 某厂java算法题实现及改进【有n个人成一圈,顺序排号(编号为1到n),从第一个人开始报数1到3报数】
一.第一种实现: 实现比较简单,直接贴现成的代码了,第一种实现: /** * 总人数 * * @param d */ private static void sortQuerry1(int d) { ...
- 经典算法:n个人围成一圈,报m的离开,最后剩下谁?
public int remainPersonNumber(int n, int m) { //输入不合法 if(n < 1 || m < 1) return -1; //初始化,存入Li ...
- n人围成一圈报数
题目:有n个人围成一圈,顺序排号.从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位 思路:用一个数组存这n个人,里面的初始状态全设为1,表示都还在圈子里面. ...
- java解答:有17个人围成一圈(编号0~16),从第0号的人开始从1报数,凡报到3的倍数的人离开圈子,然后再数下去,直到最后只剩下一个人为止,问此人原来的位置是多少号?
package ttt; import java.util.HashMap; import java.util.Map.Entry; /** * 有17个人围成一圈(编号0~16),从第0号的人开始从 ...
- 约瑟夫环问题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
首先,我最大的学习来源不是百度而是我群友~~在这里表白一波我热爱学习的群友们!然后今天群里突然有人提出了题目的这个问题:有n个人围成一圈,顺序排号.从第一个人开始报数(从1到3报数),凡报到3的人退出 ...
- java例题_37 有 n 个人围成一圈,顺序排号。从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位。
1 /*37 [程序 37 报数] 2 题目:有 n 个人围成一圈,顺序排号.从第一个人开始报数(从 1 到 3 报数),凡报到 3 的人退出圈子, 3 问最后留下的是原来第几号的那位. 4 */ 5 ...
- C语言——N个人围成一圈报数淘汰问题
<一>问题描述: 有17个人围成一圈(编号为0-16),从第 0号的人开始从 1报数, 凡报到 3的倍数的人离开圈子,然后再数下去,直到最后只剩下一个人为止. 问此人原来的位置是多少号? ...
随机推荐
- java中Class.forName与new
一.使用Class.forName 1.装载类 Class clazz = Class.forName("xx.xx.xx"); 2.初始化对象 clazz.newInstance ...
- linux的exec命令
linux的exec命令可以多进程执行,如果在浏览器访问使用http协议,会存在内存溢出和执行时间问题.
- Memcached应用总结
Memcached应用总结 memcached是一款高性能的分布式缓存系统,凭借其简单方便的操作,稳定可靠的性能广泛应用于互联网应用中,网上关于memcached介绍的资料也很多,最经典的资料就是&l ...
- 解决Cacti监控图像断断续续问题
最近cacti的图像全都是断断续续.新加的设备,图像也是这样,查看cacti 的log发现大量下面类似的错误信息:04/12/2011 03:54:37 PM - SPINE: Poller[0] H ...
- java 对list中对象按属性排序
实体对象类 --略 排序类----实现Comparator接口,重写compare方法 package com.tang.list; import java.util.Comparator; publ ...
- Jason 分享吴霁虹教授的产品模型
产品的出现都是为了解决市场上存在的某一个”疼点“或一系列的”疼点“而出现. 疼点:是一个亟需待解决的问题,对应有相应的市场,会寻找相应的解决方案.比如:用户的小孩——>因为缺钱,所以担心小孩无法 ...
- jsp之间url传值出现中文乱码
示例: T1.jsp http://localhost:8080/test/Test.action?site=北京 T2.jsp ..... <%@ page language="ja ...
- C# 中显示实现接口
接口的实现分为显示实现和隐式实现 用显示实现接口的目的就是为了,当一个类中实现多个具有相同方法的接口时,能够区分开来 在调用的时候,必须用接口调用. class Program { static vo ...
- phplib template说明
phplib template phplib有五大功能:将数据库驱动和对数据库操作完全分离:支持session:权限许可:模板:购物 车 说明:1.第一个简单的模板页first.html模板中的{ma ...
- shell脚本实现覆盖写文件和追加写文件
1.覆盖写文件 ">" date > not_append_file.txt