车厢调度问题-非_递归算法

问题描述:

假设停在铁路调度站入口处的车厢序列的编号依次为1,2,3……N。设计一个程序,求出所有由此输出的长度为N的车厢序列。

算法综述:

上一篇博文实现了解决车厢问题的递归算法。本文试图对N个车厢的全排列进行筛选,选出可能的序列。

必须声明,产生全排列的算法也有两种:递归和非递归,本文使用的是递归产生全排列。全排列的非递归算法后面再说。。。

调度站的本质是一个栈,LIFO决定了输出序列必须满足:

若以编号0,1,2,3…n-1的顺序进行调度,在一个输出序列x0,x1,x2……x(n-1)中,对于每个xi,序列x(i+1)……x(n-1)中,编号小于xi的车厢必须是递减的。


对每一个序列从后往前检查,max表示没检查到的最大元素。max初始为n-1,在没有检查到max之前(说明max已经出站),比max小的元素都应该是有序的,检查到max后,限制条件有所放宽,寻找新的max,继续检查


代码实现:

*******Stack.h*******
为了简洁点,省去了,其他文章中有。。。。
**********************



*****main.cpp*******

#include<iostream>
#include"Stack.h"
using namespace std;

int sum = 0;//计数器,每产生一个排列就+1

void Swap(int &m, int &n)//交换两个元素
{
	int temp = m;
	m = n;
	n = temp;
}

//将a中的合法序列打印出来
void Result(int a[], const int n)
{
	cout << ++sum << endl;
	for (int i = 0; i < n; i++)
		cout << a[i];
	cout << endl;
}

//在一个序列中未进行合法性检查的元素中,选出最大值,序列中该值后的比它小的元素应是递减的
int FindMax(int flag[], const int n)
{
	for (int i = n - 1; i >= 0; i--)
		if (flag[i] == 0)
			return i;
	return 0;
}

//在对一个序列进行合法性检查之前,将out和stack置为初始状态
void Reset(int flag[], const int n, Stack<int>& stack)
{
	int temp;
	while (stack.Top() != -1)
		stack.Pop(temp);
	for (int i = 0; i < n; i++)
		flag[i] = 0;
}

//缩减堆栈至其中只含有小于max的元素序列
void Reduce(Stack<int>& stack, int max)
{
	int temp;
	while (stack.Top()>max)
		stack.Pop(temp);
}

//检查全排列序列的合法性
bool Check(int a[], int flag[], const int n, Stack<int>& stack)
{
	Reset(flag, n, stack);
	int max = n - 1;//未检查的最大车厢
	//从后往前开始检查
	for (int i = n - 1; i >= 0; i--)
	{
		if (a[i] == max)
		{
			flag[a[i]] = 1;//置1,表示该元素已检查过
			max = FindMax(flag, n);
			Reduce(stack, max);
		}
		else
		{
			if (a[i] < stack.Top())
				return false;//不是递减,序列不合法
			else//a[i]<max&&a[i]>stack.Top() 没检查到max,压栈
			{
				stack.Push(a[i]);
				flag[a[i]] = 1;
			}
		}
	}
	return true;

}

//产生全排列,并对每一个序列进行合法性检查
void Perm(int a[], int flag[], int k, const int n, Stack<int>& stack)
{
	if (k == n - 1)
	{
		//如果合法,输出序列
		if (Check(a, flag, n, stack))
			Result(a, n);
	}
	else
	{
		for (int i = k; i <= n - 1; i++)
		{
			Swap(a[k], a[i]);
			Perm(a, flag, k + 1, n, stack);
			Swap(a[k], a[i]);
		}
	}
}

void main()
{
	int n;//车厢数目
	int *a;//原始铁轨
	int *flag;//已经检查过的元素
	cin >> n;
	a = new int[n];
	flag = new int[n];
	for (int i = 0; i < n; i++)
	{
		a[i] = i;
		flag[i] = 0;//初始状态,都没检查
	}
	Stack<int> stack;
	stack.Push(-1);//初始值为0,打底,用于s中没有元素时,与栈顶元素的比较

	Perm(a, flag, 0, n, stack);

	delete[]a;
	delete[]flag;
	system("pause");
}

非递归解法与递归解法的结果完全一致

n=4:14种

n=5:42种

n=6:132种

n=7:429种

n=8:1430种

    原文作者:递归算法
    原文地址: https://blog.csdn.net/hgqqtql/article/details/39737309
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞