n人过桥问题

学习了数据结构第一章的顺序表后,实验要求是使用顺序表存储数据,实现n人过桥问题,代码如下。

首先是顺序表的简单定义

const int incresize = 10;	//数组满时,每次增加10个空间
struct Node {
	char name[10];	//姓名
	int time;	//耗时
};
class SeqList {
private:
	int maxsize = 10;	//初始默认最大长度为10
	Node* people;	//动态申请内存空间的首地址
	int length = 0;	//元素个数 
public:
	SeqList();	//无参构造函数
	SeqList(const Node a[], int n);	//有参构造函数
	~SeqList();	//析构函数
	void setSeqList(const Node a[], int n);	//设置函数
	int getlength();	//返回顺序表长度
	int getby_value(const Node a);	//按值查找
	void getby_order(int i);	//按号查找
	void insert(const Node person, int i);	//插入函数
	void Delete(int i);	//删除函数
	bool isempty();	//判断是否为空
	void printdata();	//打印信息
	void sort();	//根据耗时升序排序
	int result();	//输出耗时最短结果
};

其次是顺序表的简单实现

#include <iostream>
using std::cout;
using std::endl;
#include "SeqList.h"
SeqList::SeqList() {
	people = new Node[maxsize];	//默认大小10
	length = 0;
}
SeqList::SeqList(const Node a[], int n) {
	people = new Node[2 * n];	//长度设为2n
	for (int i = 0; i < n; i++)
		people[i] = a[i];
	length = n;
	maxsize = 2 * n;	//最大长度变为2n 
}
SeqList::~SeqList() {
	delete[] people;
}
void SeqList::setSeqList(const Node a[], int n) {
	Node* oldarray = people;
	people = new Node[2 * n];
	for (int i = 0; i < n; i++)
		people[i] = a[i];
	length = n;
	maxsize = 2 * n;
	delete oldarray;
}
int SeqList::getlength() {
	return length;
}
bool SeqList::isempty() {
	return (length == 0);	//length==0返回真,否则返回假 
}
void SeqList::printdata() {
	if (isempty()) {
		cout << "无数据" << endl;
		return;
	}
	for (int i = 0; i < length; i++)
		cout << people[i].name << "用时" << people[i].time << endl;
}
int SeqList::getby_value(const Node a){
	if (isempty())
		throw 1;
	for (int i = 0; i < length; i++)
		if (a.name == people[i].name && a.time == people[i].time) {
			cout << people[i].name << "用时" << people[i].time << "在表中第" << i + 1 << "个位置" << endl;
			return i+1;
		}
	throw 2;
}
void SeqList::getby_order(int i) {
	if (i<0 || i>length)
		throw 1;
	cout << people[i-1].name << "用时" << people[i-1].time << "在表中第" << i << "个位置" << endl;
}
void SeqList::insert(const Node person, int i) {
	if (i<1 || i > length)
		throw 1;
	if (i == maxsize) {	//数组满时
		Node* oldarray = people;
		maxsize += incresize;
		people = new Node[maxsize];
		for (int j = 0; j < length; j++)
			people[j] = oldarray[j];
		people[length++] = person;	//插入后length++
		delete[] oldarray;
		return;
	}
	for (int j = length; j >= i; j--)	//数组不满时
		people[j] = people[j - 1];
	people[i - 1] = person;
	length++;
}
void SeqList::sort() {
	Node temp;	//用于交换
	for (int i = 0; i < length; i++)
		for (int j = 0; j < length - 1; j++)
			if (people[j].time > people[j + 1].time) {
				temp = people[j];
				people[j] = people[j + 1];
				people[j + 1] = temp;
			}
}
void SeqList::Delete(int i) {
	if (i<1 || i > length)
		throw 1;
	for (int j = i; j < length; j++)
		people[j - 1] = people[j];
	length--;
}

然后是解决n人过桥问题的函数

核心思路是贪心,用递归实现。
首先依据过桥耗时进行排序。并且必须遵循以下两个原则:

  • 同时过桥的两人必须相邻,以减少浪费的时间
  • 每次让对岸耗时最短的人回来

具体步骤如下:
1)先让最快的两人过桥
2)让最慢的两人过桥
3)循环
可以保证每次回来都是最快的两人,耗时最短。代码如下:

int SeqList::result() {
	int fin_time = 0;	//最终用时
	int rest = length;	//没过桥的人
	if (rest == 1)
		return people[0].time;
	sort();	//排序
	while (rest != 0) {
		fin_time += people[1].time;	//最快两人过桥
		cout << people[0].name << "和" << people[1].name << "过桥,用时" << people[1].time << endl;
		rest -= 2;
		if (rest == 0)
			return fin_time;
		fin_time += people[0].time;	//岸对面最快的人回来
		cout << people[0].name << "回来,用时" << people[0].time << endl;
		rest++;
		fin_time += people[rest].time;	//最慢两人过桥
		cout << people[rest-1].name << "和" << people[rest].name << "过桥,用时" << people[rest].time << endl;
		rest -= 2;	//过2个人
		if (rest == 0)
			return fin_time;
		fin_time += people[1].time;	//岸对面最快的人回来
		cout << people[1].name << "回来,用时" << people[1].time << endl;
		rest++;	//回来一个
	}
	return fin_time;
}

最后是测试代码

#include<iostream>
#include <windows.h>
#include "SeqList.h"
using std::cout;
using std::cin;
using std::endl;
void printmenu();
int main() {
	int n;	//输入过桥人数
	SeqList s1;
	if (s1.isempty()) {
		cout << "顺序表目前为空,请输入数据,有几人过桥?" << endl;
		cin >> n;
		Node* array = new Node[n];	//创建节点数组
		cout << "依次输入过桥人的名字和其过桥用时:" << endl;
		for (int i = 0; i < n; i++) {
			cin >> array[i].name;
			cin >> array[i].time;
		}
		s1.setSeqList(array,n);
	}
	cout << "当前有" << s1.getlength() << "人过桥" << endl;
	s1.printdata();
	system("pause");
	int choice = 1;	//选择功能
	while (choice != 0) {
		printmenu();
		cin >> choice;
		switch (choice) {
		case 0:
			exit(0);
		case 1:
			Node newpeople;
			cout << "依次输出添加人的名字和过桥用时" << endl;
			cin >> newpeople.name >> newpeople.time;
			try {
				s1.insert(newpeople, 1);
			}
			catch (int) {
				cout << "插入位置错误,该顺序表共有" << s1.getlength() << "个人" << endl;
			};
			cout << "添加后信息为:" << endl;
			s1.printdata();
			system("pause");
			break;
		case 2:
			s1.printdata();
			cout << "输入要去掉人的序号:" << endl;
			int num;
			cin >> num;
			try {
				s1.Delete(num);
			}
			catch (int) {
				cout << "删除位置错误,该顺序表共有" << s1.getlength() << "个人" << endl;
			}
			cout << "删除后信息为:" << endl;
			s1.printdata();
			system("pause");
			break;
		case 3:
			Node temp;
			cout << "依次输出要查找人的名字和过桥用时" << endl;
			cin >> temp.name >> temp.time;
			try {
				s1.getby_value(temp);
			}
			catch (int e) {
				if (e == 1)
					cout << "未储存数据" << endl;
				if (e == 2)
					cout << "未找到" << endl;
			}
			system("pause");
			break;
		case 4:
			cout << "输入查找表中第几个人" << endl;
			cin >> num;
			try {
				s1.getby_order(num);
			}
			catch (int) {
				cout << "查找序号错误,该顺序表共有" << s1.getlength() << "个人" << endl;
			}
			system("pause");
			break;
		case 5:
			s1.sort();
			cout << "排序后信息为:" << endl;
			//此处没有break,排序后输出信息
		case 6:
			s1.printdata();
			system("pause");
			break;
		case 7:
			cout << "共用时" << s1.result() << endl;
			system("pause");
			break;
		default:
			cout << "请输入有效序号" << endl;
			system("pause");
		}
	}
	return 0;
}
void printmenu() {
	system("cls");
	cout << "1)添加一个人\t\t\t\t2)去掉一个人\n" <<
			"3)根据信息查找一个人\t\t\t4)根据序号查找一个人\n" <<
			"5)对过桥的人根据用时排序\t\t6)输出信息\n" <<
			"7)输出答案\n" << endl;
	cout << "输入对应的序号选择功能,输入0退出程序" << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值