2021.12大二上學期數據結構結課設計

敢死隊問題
問題描述: 有 M 個敢死隊員要炸掉敵人的一碉堡,誰都不想去,排長決定用輪迴數數的辦法來決 定哪個戰士去執行任務。如果前一個戰士沒完成任務,則要再派一個戰士上去。現給每個戰 士編一個號,大家圍坐成一圈,隨便從某一個戰士開始計數,當數到 N 時,對應的戰士就 去執行任務,且此戰士不再參加下一輪計數。如果此戰士沒完成任務,再從下一個戰士開始 數數,被數到第 N 時,此戰士接着去執行任務。以此類推,直到任務完成爲止。 排長是不願意去的,假設排長爲 1 號,請你設計一程序,求出從第幾號戰士開始計數 才能讓排長最後一個留下來而不去執行任務。
基本要求: (1)輸入隊伍人數 M 和計數 N,輸出排長指定的開始序號; (2)至少採用兩種不同的數據結構的方法實現。

感謝朗哥獻祭“松籟響起之時”給我們小組抽到了最簡單的課程設計題目hhhhhhhhhhhhhhhhhhhhh
這題放到洛谷上也就普及+頂天了
以下爲思路及優化

/*
 * 感謝丁老師提供的撲克牌舉例演示
 * 需求分析:
 *		輸入:總人數m,報數要求n
 *		輸出:滿足最後只剩排長一人的一次報數中第一個報數的人的編號
 *
 *		最後只剩排長一人即最後一個前去任務的人是排長
 *		即排長前去任務後洞中無人,則該次報數爲符合題意的報數
 *		若一次派遣中,排長前去任務,此後洞中還有戰士,則該次報數爲不合題意的報數
 * 名詞註解:
 *		一次派遣:指從1報到n,報到n的人出局。
 *		一次報數:指從第一次派遣直到排長報數後前去任務
 *
 * 第一次會議記錄:11.22上午9時。明確所使用兩種數據結構爲順序表、鏈式隊列。聶樂恆負責順序表實現,楊朗負責鏈式結構隊列實現。各自確認了數據結構解決問題過程
 * 第二次會議記錄:11.29上午9:30。就如何用隊列解決問題產生意見分歧。yl思路爲僅改變尾指針指向頭指針位置,nlh思路爲頭指針和尾指針均正常向後移動(按照常規隊列進行處理)以下爲nlh思路部分代碼
Queue que;//定義隊列
a[i] = i+1;//a數組存的是隊員編號
int x;
for(int i=0; i<m; ++i) {//一次報數中第一個報數的人,從0~m-1遍歷
	for(int j=0; j<m; ++j)//隊員圍成圈,從第一個報數的人開始向後延伸,隊員入隊
		que.enqueue(a[(i+j)%n]);
	do{//一次派遣
		for(int k=0; k<n-1; ++k)//報數,報到1~n-1,不需前去任務
			que.enqueue(que.dequeue());
		x = que.dequeue();//報數,報到n,前去任務。x爲前去任務的人的編號
	}while(x!=0);//當排長前去任務時停止報數
	if(que.empty())//排長前去任務後山洞內無人,是一次符合題意的報數
		cout << i << "第一個報數" << endl;
	while(!que.empty())//隊列置空
		que.dequeue();
}
 *
 * 第一次優化:Length()函數求山洞內剩餘人數爲遍歷求得,可在類內部定義變量length,每次派遣--length
 * 優勢分析:支持每次派遣之間的n不同。實際意義在於,可能某次報數過程中,某戰士爲增大計算難度使每次派遣報數要求n不同。Get(x)支持x改變依然實現報數要求
 */

yl鏈式隊列代碼

點擊此處查看代碼LinkQueue.h
#pragma once
#include <iostream>
#define nullptr NULL

using namespace std;
const int MaxSize = 100;

template<typename DataType>
struct Node
{
	DataType data = 0;												//此戰士的編號
	bool completed = false;											//默認每個戰士都不能完成任務
	Node<DataType>* next = nullptr;											
};

template<typename DataType>
class LinkQueue
{
public:
	LinkQueue();													//初始化空的鏈隊列
	~LinkQueue();													//釋放鏈隊列的存儲空間
	void EnQueue(DataType x, bool y);								//入隊操作,將元素x和y入隊
	DataType DeQueue();												//出隊操作,將指定的對頭元素出隊
	int Length();													//返回當前隊列的長度
	bool Empty();													//判斷鏈隊列是否爲空
	bool LeaderSurvival();											//判斷鏈隊列中是否只剩下隊長
	void Work(int M, int N);										//求解問題
private:
	Node<DataType>* front, * rear;									//聲明隊頭指針和隊尾指針
	int length = 0;													//記錄當前隊列的長度
};

template<typename DataType>
LinkQueue<DataType>::LinkQueue()									//函數功能:初始化空的鏈隊列
{
	Node<DataType> *s = nullptr;
	s = new Node<DataType>;
	s->next = nullptr;
	front = rear = s;												//將隊頭指針和隊尾指針都指向頭結點s
}

template<typename DataType>
LinkQueue<DataType>::~LinkQueue()									//函數功能:釋放鏈隊列的存儲空間
{
	Node<DataType>* p = front;
	while(!Empty())													//釋放每一個結點的存儲空間
	{
		front = front->next;
		delete p;
		p = front;													//工作指針後移
	}
}

template<typename DataType>
void LinkQueue<DataType>::EnQueue(DataType x, bool y)				//函數功能:將元素x和y入隊
{
	Node<DataType>* s = nullptr;
	s = new Node<DataType>;											//申請結點s
	s->data = x;
	s->completed = y;
	s->next = nullptr;
	rear->next = s;													//將結點s插入到隊尾
	rear = s;
	++length;
}

template<typename DataType>
DataType LinkQueue<DataType>::DeQueue()								//函數功能:將指定的隊頭元素出隊
{
	DataType x;
	bool y;
	if(Empty()) throw "隊列已經爲空。";
	Node<DataType>* p = front->next;								//暫存隊頭元素
	x = p->data;
	y = p->completed;
	front->next = p->next;											//將隊頭元素所在結點摘鏈
	if(p->next == nullptr) rear = front;							//出隊前隊列長度爲1
	delete p;
	--length;
	return x;
}

template<typename DataType>
int LinkQueue<DataType>::Length()									//函數功能:返回當前隊列的長度
{
	//cout << "front->data:" << front->data << "  **  " << "rear->data:" << rear->data << endl;
	return length;
}

template<typename DataType>
bool LinkQueue<DataType>::Empty()									//函數功能:判斷隊列是否爲空
{
	return (length == 0);
}

template<typename DataType>
bool LinkQueue<DataType>::LeaderSurvival()							//函數功能:判斷隊列中是否只剩下隊長
{
	if ((length == 1) && (rear->data == 1))
		return true;
	return false;
}

template<typename DataType>
void LinkQueue<DataType>::Work(int M, int N)						//函數功能:求解敢死隊問題
{
	int a[MaxSize], x;
	for (int i = 0; i < M; i++)                                     //討論從0~10開始時,怎樣才能使排長最後一個去執行任務
	{
		a[i] = i + 1;
		for (int j = 0; j < M; j++)                                 //將M個敢死隊員入隊
			EnQueue(a[(i + j) % M], false);
		do                                                          //數數並派遣隊頭的敢死隊員去執行任務
		{
			//cout << "Testing:" << i << "  **  Length:" << Queue.Length() << "  **  ";
			for (int j = 0; j < N - 1; j++)
				EnQueue(DeQueue(), false);
			x = DeQueue();
			if (LeaderSurvival())
				cout << "排長可以指定的開始序號爲:" << i + 1 << endl;
		} while (x != 1);

		while (Empty() != true)
			DeQueue();
	}
}

nlh順序表

點擊此處查看代碼SeqList.h
#pragma once
#include <iostream>
using namespace std;
const int Maxn = 101;

int a[Maxn];
class SeqList {
public:
	SeqList() {//置零
		m = n = id = 0;
		for (int i = 0; i < Maxn; ++i)
			data[i] = 0;
		length = 0;
	}
	void Set(int M, int N) {
		m = M, n = N, id = 1;
		for (int i = 1; i <= m; ++i)
			data[i] = a[i] = i;
		length = m;
	}
	void Reset(int a[], int begin) {//重置順序表內容,本次報數從begin開始
		for (int i = 1; i <= m; ++i)
			data[i] = a[i];
		id = begin;
		length = m;
	}
	int Length() {//返回目前隊伍長度
		return length;
	}
	int Get(int x) {//查找從id號隊員開始報數目前第x位的值
		int count = 0, i = id-1;//i=id-1是因爲下面while中第一句++i
		while (count != x) {
			++i;
			if (i > m) i = 1;
			if (data[i] != 0)
				++count;
		}
//		cout << i << ' ';//輸出該次派出執行任務的戰士編號
		data[i] = 0;
		--length;
		id = i;
		return i;
	}
	void Work() {//問題求解,輸出合法編號
		for (int i = 1; i <= m; ++i) {
			Reset(a, i);//重置數組,本次報數第一個報數的人編號爲i
			while(Get(n) != 1);//執行派遣直到排長去執行任務
			if(Length() == 0)//排長去執行任務後洞中無人
				cout << "從第 " << i << " 號戰士開始計數能讓排長最後一個留下來" << endl;
		}
	}
private:
	int data[Maxn];//data[i] = i,即編號對應編號
	int m, n, id;//m爲初始隊伍人數,n爲報數數字,id爲下次開始報數的人的編號
	int length;//剩餘人數。*第一次優化
};

主文件

點擊此處查看代碼main.cpp
#include <iostream>
#include "SeqList.h"
#include "LinkQueue.h"
using namespace std;

int main(void) {
	int m, n;
	int op;
	LinkQueue<int> Queue;
	SeqList list;
	do {
		cout << endl << endl;
		cout << "****************" << endl;
		cout << "請輸入指令" << endl;
		cout << "0:停止程序" << endl;
		cout << "1:鏈式隊列解決問題" << endl;
		cout << "2:順序表解決問題" << endl;
		cout << "****************" << endl << endl;
		cin >> op;
		if (op == 0) break;

IN:		cout << "****************" << endl;
		cout << "請輸入隊伍總人數m和報數要求n" << endl;
		cout << "****************" << endl;
		cin >> m >> n;
		if (n < 0 || m < 0 || m > 101) {
			cout << "輸入數據有誤!請重新輸入" << endl;
			goto IN;//重新輸入
		}
		switch (op) {
			case 1:
				Queue.Work(m, n);
				break;
			case 2:
				list.Set(m, n);
				list.Work();
				break;
			case 0:
				break;
			default:
				cout << "輸入錯誤!請重新輸入" << endl;
		}
	}while (op != 0);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章