天天看点

约瑟夫环的两种常见解法:链表解法和递归解法(C++版)

约瑟夫环问题: 

约瑟夫环的两种常见解法:链表解法和递归解法(C++版)

       直观解法 :链表解法。创建链表,判断删除节点是在N/2之前还是之后,进行模除运算,若在之前则从前往后遍历,保留间隔内数字,直到扫描到本次遍历结尾,输出本次遍历被删除的节点;若在之后,则从后往前遍历间隔内数字,直到扫面到本次遍历开头,输出本次遍历被删除的节点,逐次模除运算,最后的节点即为最终保留结果。

#include<iostream>
#include<list>

using namespace std;

int main()
{
	int mPrime, numLeft;
	int N, M;
	list<int> mList;
	list<int>::iterator iter;
	cout << "Enter the N(of people) & M(of passes before elimination ) : ";
	cin >> N >> M;
	numLeft = N;
	mPrime = M % N;
	for(int i = 1; i <= N; i++){
		mList.push_back(i);
	}
	iter = mList.begin();
	for(int i = 0; i < N; i++)
	{
		mPrime %= numLeft;
		//pass forward
		if(mPrime <= numLeft/2)
		{
			for(int j = 0; j < mPrime; j++)
			{
				iter++;
				if(iter == mList.end())
				{
					iter = mList.begin();
				}
			}	
		}
		//pass backworfd
		else
		{
			for(int j = 0; j < mPrime; j++)
			{
				if(iter == mList.begin())
				{
					iter = --mList.end();
				}
				else
				{
					iter--;
				}
			}
		}
		//output the selected one
		cout << *iter << " ";
		iter = mList.erase(iter);
		if(iter == mList.end())
		{
			iter = mList.begin();
		}
	}
	cout << " done ." << endl;
	return 0;
}

//run with N = 7, M = 3
           

      数学解法:第一个人出列后,剩余(N- 1)人组成新的约瑟夫环,递归调用,当最后只剩一人是即为所求结果。地推表达式:

约瑟夫环的两种常见解法:链表解法和递归解法(C++版)
#include <iostream>
#include <list>
using std::cout;
using std::endl;
using std::cin;
using std::list;

int josephus(int N, int M);

int main()
{
	int N, M;
	cout << "Enter the N(of people) & M(of passes before elimination ) : ";
	cin >> N >> M;
	cout << "the last one is : " << ( 1 + josephus(N, M)) << endl;
    return 0;
}

int josephus(int N, int M)
{
	if(N == 1)
	{
		return 0;
	}
	else
	{
		return (josephus(N - 1, M) + M) % N;
	}
}

//run with N = 7, M = 2 (passes before elimination)
           

practice makes perfects!

继续阅读