PTA|7-3 生死者游戏 (30分)【数据结构】

题目简介:
有n个旅客同乘一条船,因为船发生故障,最多只能留下一半旅客。大家议定如下办法:n个人围成一圈,由第一个人起,依次报数,报到m的人必须被扔进大海。如此循环。问最后哪些旅客仍留在船上?每个人都有一个m值,当他被扔进大海后,m的值改为这个人的m值。m的初值由第一个人决定。
输入格式:
输入共二行,第一行为人数n,第二行为n个整数,代表每个人的m值。
输出格式:
在一行中输剩下乘客的编号(用%3d格式输出)。

输入样例:

10
2 3 4 3 2 4 3 6 3 2

输出样例:

  1  4  6  8  9

思路:
我最初的想法是建立一个循环链表,一个头指针L和两个循环指针p、q去循环删除数据,但是写着写着发现这个思路虽然可行,但要考虑的特殊情况多,比如遇到要删的数据为1时,又或是要删除首结点时。
所以倒不如不去真正的删除结点,而是在结构体中多加入一个元素来记录其状态,还留在船上的标记为1,扔海里的为0,在循环和输出时直接判断flag的值即可。

附上代码:

#include<stdio.h>
#include <stdlib.h>
//定义结构体
typedef  struct  LNode
{   int  num;  //记录编号
    int  data; //记录其m值
    int  flag; //记录状态(生1死0)
    struct  LNode  *next;
}LNode, *LinkList; 

int main()
{
	int m,n,i,half,cnt=0;
	scanf("%d",&n);  //输入人数
	//判断n的奇偶,题目中说最多只能留下一半的人,假如n=9,则要“删除”5人
	if(n%2!=0) half=(n+1)/2;  //为奇数时+1再除2
	else half=n/2;
	LinkList L,p,q; 
	L=(LNode *)malloc(sizeof(LNode)); 
	scanf("%d",&L->data);
	L->num=1; L->flag=1;
	q=L;
	for(i=1;i<n;i++)   //建立循环链表
	{  
		p=(LNode *)malloc(sizeof(LNode));
		scanf("%d",&p->data);
		p->num=i+1;p->flag=1;
		q->next=p;
		q=p;
	}
	q->next=L; //首位相连 
	//开始删除
	m=L->data;  //记录首结点的m值
	p=L;
	for(i=0;i<half;i++){
		for(cnt=1;cnt<m;){ //cnt用于记录已经数的次数
			if(p->flag!=0)  //指到flag为1的人时cnt加1
				cnt+=1;
			p=p->next;
		}
		while(p->flag==0) p=p->next;//让p跳过flag已经为0的位置,防止flag重复置0
		p->flag=0;
		m=p->data;   //记录被删除数据的m值,用于下次循环
		p=p->next;
	}
	//判断状态,输出
	p=L;
	for(i=0;i<n;i++){
		if(p->flag==1)
			printf("%3d",p->num);
		p=p->next;
	}
	return 0;
}

提交结果:
在这里插入图片描述

希望对你有帮助
若有不足请指出

下面是用C语言实现的约瑟夫双向生死游戏的代码,你可以参考一下: ```c #include <stdio.h> #include <string.h> #define MAX 100 // 定义一个结构体表示旅客 struct passenger { char name[20]; int number; }; int main() { // 初始化输入参数 int p, m, n, q; printf("请输入旅客总人数p、正向报数m、反向报数n、剩余人数q:"); scanf("%d %d %d %d", &p, &m, &n, &q); // 定义旅客数组 struct passenger passengers[MAX]; int i, j; // 初始化旅客 for (i = 0; i < p; i++) { sprintf(passengers[i].name, "passenger%d", i+1); passengers[i].number = i+1; } // 定义出列数组 int out_list[MAX]; memset(out_list, 0, sizeof(out_list)); int out_index = 0; // 开始游戏 int count = 0; int pos = 0; int direction = 1; while (p > q) { count++; if (direction == 1) { if (count == m) { out_list[out_index++] = passengers[pos].number; printf("%s离开了\n", passengers[pos].name); for (j = pos; j < p-1; j++) { passengers[j] = passengers[j+1]; } p--; count = 0; } else { pos++; } if (pos >= p) { pos = 0; } if (p == q) { break; } } else { if (count == n) { out_list[out_index++] = passengers[pos].number; printf("%s离开了\n", passengers[pos].name); for (j = pos; j < p-1; j++) { passengers[j] = passengers[j+1]; } p--; count = 0; } else { pos--; } if (pos < 0) { pos = p-1; } } if (direction == 1 && count == m) { direction = -1; count = 0; } if (direction == -1 && count == n) { direction = 1; count = 0; } } // 输出剩余旅客 printf("剩余的旅客为:\n"); for (i = 0; i < p; i++) { printf("%s\t%d\n", passengers[i].name, passengers[i].number); } // 输出出列的旅客 printf("出列的旅客为:\n"); for (i = 0; i < out_index; i++) { printf("%d\t", out_list[i]); } printf("\n"); return 0; } ``` 在该代码中,我们使用了一个结构体来表示旅客,其中包含旅客的姓名和编号。我们通过循环报数并出列的方式实现了约瑟夫双向生死游戏,并输出了离开和剩余的旅客信息。你可以根据需要进行修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值