1. 程式人生 > >格雷碼、全排列、約瑟夫環、m個元素中求n個元素的所有集合

格雷碼、全排列、約瑟夫環、m個元素中求n個元素的所有集合

格雷碼:

格雷碼是指,通過0-1的串來求出對應位數的所有可能。例如2的格雷碼:00、01、10、11

//格雷碼  例如2:00 01 10 11
void print(vector<int> &veNum)
{
	for (int i = 1; i < veNum.size(); ++i)
		cout << veNum[i] << " ";
	cout << endl;
}
void printallnum(int iNum)
{
	if (iNum <= 0)
		return;
	vector<int> veNum(iNum + 1);
	int ipos = iNum;
	while (true)
	{
		ipos = iNum;
		while (ipos > 0 && veNum[ipos] == 1) veNum[ipos--] = 0;
		if (ipos == 0)
			break;
		else
			veNum[ipos] = 1;
		print(veNum);
	}
}
int main()
{
	int iNum = 0;
	cin >> iNum;
	printallnum(iNum);
	return 0;
}

求n個元素的所有可能的組合:

給定n個元素,求著n個元素的所有可能,也就是他的所有子集。這可以看成是格雷碼問題的一種變形問題:

//所有可能的集合 12-> 1 2 12  格雷碼的變形
void print(vector<int> &veNum, int ar[], int iLen)
{
	for (int i = 1; i < veNum.size(); ++i)
	{
		if (veNum[i])
			cout << ar[i - 1];
	}
	cout << endl;
}
void allprint(int ar[], int iLen)
{
	if (ar == NULL || iLen <= 0)
		return;
	vector<int> veNum(iLen + 1);
	while (true)
	{
		int iPos = iLen;
		while (iPos > 0 && veNum[iPos] == 1) veNum[iPos--] = 0;
		if (iPos == 0)
			return;
		else
			veNum[iPos] = 1;
		print(veNum, ar, iLen);
	}
}
int main()
{
	int ar[] = { 1, 2, 3, 4 };
	int iLen = sizeof(ar) / sizeof(ar[0]);
	allprint(ar, iLen);
	return 0;
}

m個元素中求n個元素的所有集合:

求m個元素的集合中,任意n個元素對應的所有集合。

void allprint(int iAllLen, int n)
{
	if (iAllLen < n)
		return;
	else if (iAllLen == n)
	{
		for (int i = 0; i < n; ++i)
			cout << i+1;
		cout << endl;
	}
	else
	{
		vector<int> veNum(iAllLen + 1);
		for (int i = 0; i <= iAllLen; ++i) veNum[i] = i;
		//列印初始值
		for (int i = 1; i <= n; ++i)
			cout << veNum[i];
		cout << endl;
		int iposition = n ;
		while (1)
		{
			if (veNum[n] == iAllLen)
				iposition--;
			else
				iposition = n;
			veNum[iposition]++;
			for (int i = iposition + 1; i <= n; ++i)
				veNum[i] = veNum[i - 1] + 1;
			for (int i = 1; i <= n; ++i)
				cout << veNum[i];
			cout << endl;
			if (veNum[1] >= iAllLen - n + 1)
				break;
		}
	}
}
int main()
{
	int iAllLen = 6;
	int n = 4;
	allprint(iAllLen, n);
	return 0;
}

上邊的求解是假設初始的m的集合是從1開始並且順序增加的數字。如果是任意的陣列集合,可以根據求出的數字來確定對應的下標進行求解該問題。

//m個元素中n個元素的所有集合 改問題的變形 詳情參考該問題
void allprint(int ar[], int iAllLen, int n)
{
	if (iAllLen < n)
		return;
	else if (iAllLen == n)
	{
		for (int i = 0; i < n; ++i)
			cout << ar[i];
		cout << endl;
	}
	else
	{
		vector<int> veNum(iAllLen + 1);
		for (int i = 0; i <= iAllLen; ++i) veNum[i] = i;
		//列印初始值
		for (int i = 1; i <= n; ++i)
			cout << ar[veNum[i] - 1];
		cout << endl;
		int iposition = n;
		while (1)
		{
			if (veNum[n] == iAllLen)
				iposition--;
			else
				iposition = n;
			veNum[iposition]++;
			for (int i = iposition + 1; i <= n; ++i)
				veNum[i] = veNum[i - 1] + 1;
			for (int i = 1; i <= n; ++i)
				cout << ar[veNum[i] - 1];
			cout << endl;
			if (veNum[1] >= iAllLen - n + 1)
				break;
		}
	}
}
int main()
{
	int ar[] = { 3, 5, 9, 1, 0, 5 };
	int iAllLen = sizeof(ar) / sizeof(ar[0]);
	int n = 3;
	allprint(ar, iAllLen, n);
	return 0;
}

--------------------------------------------------------------------------優雅分界線-------------------------------------------------------------------------------

約瑟夫環問題:

m個士兵,因為被敵人包圍卻不想俘虜,決定報數決定生死。沒報數到3的人自殺,剩下的人繼續報數,求最後活下的兩個人。

//思路:新開闢一個空間 用於儲存
int nextpos(int ipos, int iRingNum, vector<int> &veNum)
{
	ipos = ipos + 1 >= iRingNum ? 0 : ipos + 1;
	while (ipos < iRingNum)
	{
		if (veNum[ipos] == 1)
			ipos++;
		else
			return ipos;
		if (ipos == iRingNum)
			ipos = 0;
	}
}
void printring(int iRingNum, int iLiveNum)
{
	if (iRingNum <= 0 || iLiveNum <= 0 || iRingNum < iLiveNum)
		return;
	vector<int> veNum(iRingNum);  //儲存的vector
	int iAllNum = 0;  //總體多少個
	int iNum = 0;   //對iLiveNum求餘之後下標
	int j = 1;  
	for (int i = 0;;)  //下標
	{
		j++;
		i = nextpos(i, iRingNum, veNum);
		if (j == iLiveNum)  //要死的寶寶
		{
			veNum[i] = 1;
			iAllNum++;  //共死了多少個寶寶
			if (iRingNum - iAllNum <= iLiveNum - 1)  //存活的寶寶
				break;
			j = 0;
		}
	}
	for (int i = 0; i < veNum.size(); ++i)
		cout << veNum[i] << " ";
	cout << endl;
}
int main()
{
	int iRingNum = 0;
	int iLiveNum = 0;
	cin >> iRingNum;
	cin >> iLiveNum;
	printring(iRingNum, iLiveNum);
	return 0;
}

全排列:

//全排列
/////////庫方法
int main()
{
	int ar[] = { 1, 2, 3 };
	int iLen = sizeof(ar) / sizeof(ar[0]);
	do
	{
		for (int i = 0; i < iLen; ++i)
		cout << ar[i];
		cout << endl;
	} while (next_permutation(ar, ar + iLen));
	return 0;
}
/////////普通方法
void allprint(int ar[], int iLen, int iLeft)
{
	if (iLeft >= iLen)
	{
		for (int i = 0; i <= iLen; ++i)
			cout << ar[i];
		cout << endl;
	}
	else
	{
		for (int i = iLeft; i <= iLen; ++i)
		{
			int iTmp = ar[iLeft];
			ar[iLeft] = ar[i];
			ar[i] = iTmp;
			allprint(ar, iLen, iLeft + 1);
			iTmp = ar[iLeft];
			ar[iLeft] = ar[i];
			ar[i] = iTmp;
		}
	}
}
void allprint(int ar[], int iLen)
{
	if (ar == NULL || iLen <= 0)
		return;
	allprint(ar, iLen-1, 0);
}
int main()
{
	int ar[] = { 1, 2, 3 };
	int iLen = sizeof(ar) / sizeof(ar[0]);
	allprint(ar, iLen);
	return 0;
}

此致

敬禮