题目链接:
https://wenku.baidu.com/view/d8253e24f90f76c660371ac2.html?from=search
问题描述:
N个教徒和N个非教徒在深海上遇险,必须将一半的人投入海中, 其余的人才能幸免于难,于是他们想了一个办法: 2N个人围成一圈,从第一个人开始依次循环报数,每数到第9个人就将他扔进大海,如此循环直到只剩下N个人为止。问怎样的站法,才能使得每次投入大海的都是非教徒。
输入:
输入文件由一行构成,就是N的值
输出:
输出文件是一行字符串,字符串由N个@字符(代表教徒)和N个+字符(代表非教徒)排列组成。该排列使得按照提述方法每次投入大海的都是非教徒。
输入样本:
15
输出样本:
@@@@+++++@@+@@@+@++@@+++@++@@+
思路
假设队里这里有2N个教徒,扔出去的“变成”非教徒,就是数到9的那个“变成”非教徒,变过的人再数到的就跳过,因为这个人已经扔出队伍了;话说这道题真的很有意思~
这里N值就不改成输入式获取了,有爱自改;
思路1:边数边翻牌子
List容器
int n = 15;
Console.WriteLine("N:"+ n);
List<int> normal = new List<int>();// 校验用
List<string> list = new List<string>();
for (int l = 0; l < 2*n; l++)// 添加所有都是教徒的队伍
{
list.Add("@");
}
for (int normalCount = 0,k = 1,i = 1; normalCount < n; k++)
{
if (k >= 2 * n)// 保证索引循环
{
k = 0;
}
if (list[k] == "@")// 这里数到教徒才计数+1并进行替换,因为替换过的都变成非教徒,非教徒替换后如果第二轮遇上时应该跳过,因为第一轮时已经被抽取出来,相当于是个空位
{
i++;// 计数+1
if (i % 9 == 0)// 9的倍数时将原来的教徒换成非教徒
{
list[k] = "+";
normal.Add(k + 1);// 校验用
normalCount++;// 非教徒+1
}
}
}
foreach (var item in list)
{
Console.Write(item);
}
Console.WriteLine();
normal.Sort();
foreach (var item in normal)// 显示剔除序号(=索引+1)
{
Console.Write(item+"\t");
}
Console.WriteLine();
//Console.WriteLine("校验:\n@@@@+++++@@+@@@+@++@@+++@++@@+");
Console.WriteLine("取出的成员:");
// 模拟抽取过程校验
for (int getOutCount = 0, i = 1; getOutCount < n; i++)
{
if (i == 9)
{
if (i > list.Count)
{
i %= list.Count;
}
Console.Write(list[i - 1]);// 即将取出的人
list.RemoveAt(i - 1);// 取出
getOutCount++;// 取出人数+1
// 下面把数过的人放到队尾组成新的队伍给下次循环数
List<string> fontList = new List<string>();
fontList.AddRange(list.GetRange(0, i-1));
list.RemoveRange(0, i-1);
list.AddRange(fontList);
i = 1;// 重新数9个
}
}
Console.ReadKey();
Queue容器
int n = 15;
Console.WriteLine("N:" + n);
Queue<Dictionary<int,char>> queue = new Queue<Dictionary<int, char>>();
for (int i = 1; i <= 2*n; i++)
{
queue.Enqueue(new Dictionary<int, char>{ { i, '@' } });
}
int delCount = 0;// 非教徒数
while (delCount < n)
{
for (int j = 0; j < 9; j++)
{
Dictionary<int, char> man = queue.Dequeue();
int key = man.Keys.First();
char value = man.Values.First();
if (value == '+')
{
j--;// 这个已经是脱离队伍的,所以索引回退
}
else if (j == 9 - 1)
{
value = '+';
delCount++;
}
queue.Enqueue(new Dictionary<int, char> { { key, value } });
}
}
while (queue.Peek().Keys.First() != 1) // 还原顺序
{
queue.Enqueue(queue.Dequeue());
}
foreach (var item in queue)
{
Console.Write(item.Values.First());
}
Console.WriteLine();
思路2:模拟【业务】操作
直接还原情景模拟抽取操作,操作完后按原来序号排序
int n = 5;
Console.WriteLine("N:" + n);
Queue<Dictionary<int,char>> queue = new Queue<Dictionary<int, char>>();
for (int i = 1; i <= 2 * n; i++)
{
queue.Enqueue(new Dictionary<int, char> { { i, '@' } });
}
SortedDictionary<int, char> resultList = new SortedDictionary<int, char>();// 结果队列
while (queue.Count > n)
{
for (int j = 0; j < 9; j++)
{
Dictionary<int, char> men = queue.Dequeue();
int key = men.Keys.First();
char value = men.Values.First();
if (j != 9 - 1)
{
queue.Enqueue(men);
}
else
{
value = '+';
}
if (resultList.ContainsKey(key))
{
resultList[key] = value;
}
else
{
resultList.Add(key, value);
}
}
}
foreach (var item in resultList)
{
Console.Write(item.Value);
}
Console.WriteLine();
Console.ReadKey();
结果