1. 程式人生 > >全排列(遞迴與函式實現)

全排列(遞迴與函式實現)

Ignatius and the Princess II

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9892    Accepted Submission(s): 5777

Problem Description

Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess."

"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem?

Input

The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file.

Output

For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.

Sample Input

6 4 11 8

Sample Output

1 2 3 5 6 4 1 2 3 4 5 6 7 9 8 11 10

題目大意:輸入一個n,求n的全排列,在輸入一個m,求按照字典序第m個排列順序,輸出出來。

法一:遞迴順序輸出:

因為這個題目m只有1e+5範圍,所以完全可以遍歷,然後輸出,按順序遍歷,找到第m個後儲存然後輸出:

ac:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h> 

#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

#define ll long long
#define da    0x3f3f3f3f
#define xiao -0x3f3f3f3f
#define clean(a,b) memset(a,b,sizeof(a))// 雷打不動的標頭檔案

bool biaoji[1005];//標記 
int shuzu[1005];//儲存變數 
int n,m,sum,f;
//數字個數,第幾個排列,當前第幾個排列,是否找到 

void dfs(int i,int j)
{
	if(j==n)// 排列完成 
	{
		sum++;//個數++ 
		if(sum==m)//確定是該排列 
			f=1;//f=1 
		return ;
	}
	for(i=1;i<=n;++i)
	{
		if(biaoji[i]==0)//沒被標記過 
		{
			biaoji[i]=1;//標記 
			dfs(i,j+1);//排列數的個數+1 
			biaoji[i]=0;//取消標記 
			if(f)//是該數 
			{
				shuzu[j]=i;//入陣列 
				break;//接下來就不用 找了 
			}
		}
	}
}

int main()
{
	while(cin>>n>>m)
	{
		sum=0;
		f=0;
		clean(shuzu,0);
		clean(biaoji,0);
		int i,j;
		for(i=1;i<=n;++i)//每個數都找一遍 ,因為是初始的第一個數,所以必定都沒被標記
		{
			biaoji[i]=1;// 標記該數 
			dfs(i,1);// 第一個數字,排列了幾個數字了 
			biaoji[i]=0;//讓這個標記取消 
			if(f)	//若找到目標排列 
			{
				shuzu[0]=i;//第一個元素插入 
				break;//結束迴圈 
			}
		}
		for(i=0;i<n-1;++i)//按順序輸出 
			cout<<shuzu[i]<<" ";
		cout<<shuzu[n-1]<<endl;
	}
}

法二:運用全排列函式排列,輸出第m個排列:

這個函式我。。一開始不知道,傻傻的手寫dfs。。

 這裡先說兩個概念:“下一個排列組合”和“上一個排列組合”,對序列 {a, b, c},每一個元素都比後面的小,按照字典序列,固定a之後,a比bc都小,c比b大,它的下一個序列即為{a, c, b},而{a, c, b}的上一個序列即為{a, b, c},同理可以推出所有的六個序列為:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}沒有上一個元素,{c, b, a}沒有下一個元素。

    1)next_permutation:求下一個排列組合 

a.函式模板:next_permutation(arr, arr+size);
b.引數說明:
  arr: 陣列名
  size:陣列元素個數
c.函式功能: 返回值為bool型別,噹噹前序列不存在下一個排列時,函式返回false,否則返回true,排列好的數在陣列中儲存

d.注意:在使用前需要對欲排列陣列按升序排序,否則只能找出該序列之後的全排列數。
    比如,如果陣列num初始化為2,3,1,那麼輸出就變為了:{2 3 1} {3 1 2} {3 2 1}

2)prev_permutation:求上一個排列組合

a.函式模板:prev_permutation(arr, arr+size);
b.引數說明:
  arr: 陣列名
  size:陣列元素個數
c.函式功能: 返回值為bool型別,噹噹前序列不存在上一個排列時,函式返回false,否則返回true
d.注意:在使用前需要對欲排列陣列按降序排序,否則只能找出該序列之後的全排列數。

#include <iostream>
#include <algorithm>
using namespace std;
int main ()
{
    int arr[] = {3,2,1};
    cout<<"用prev_permutation對3 2 1的全排列"<<endl;
    do
    {
        cout << arr[0] << ' ' << arr[1] << ' ' << arr[2]<<'\n';
    }
    while ( prev_permutation(arr,arr+3) );      ///獲取上一個較大字典序排列,如果3改為2,只對前兩個數全排列

    int arr1[] = {1,2,3};
    cout<<"用next_permutation對1 2 3的全排列"<<endl;
    do
    {
        cout << arr1[0] << ' ' << arr1[1] << ' ' << arr1[2] <<'\n';
    }
    while ( next_permutation(arr1,arr1+3) );      ///獲取下一個較大字典序排列,如果3改為2,只對前兩個數全排列
    ///注意陣列順序,必要時要對陣列先進行排序

    return 0;
}

這是兩者的區別,下面是ac程式碼:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h> 

#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

#define ll long long
#define da    0x3f3f3f3f
#define xiao -0x3f3f3f3f
#define clean(a,b) memset(a,b,sizeof(a))// 雷打不動的標頭檔案

int shuzu[1010];
int n,m;

int main()
{
	while(cin>>n>>m)
	{
		clean(shuzu,0);
		int i,j;
		for(i=1;i<=n;++i)
			shuzu[i]=i;
		int sum=0;
		do{
			sum++;
			if(sum==m)
			{
				for(i=1;i<n;++i)
					cout<<shuzu[i]<<" ";
				cout<<shuzu[n]<<endl;
				break;
			}
			
		}while(next_permutation(shuzu+1,shuzu+n+1));
	}
}

相關推薦

排列函式實現

Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s

Java下實現無重字串的排列和回溯方法

開發十年,就只剩下這套架構體系了! >>>   

斐波那契數列的python實現list實現

斐波那契數列概念 斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、13、21、34、……

用DFS輸出n個數的排列實現

最近在研究DFS,可能腦子不太夠吧,很多題都不知道怎麼實現,全排列應該是最簡單的題了。執行成功的程式碼如下所示:#include<stdio.h> #include<iostream> #include<string.h> using na

Lintcode 15.排列 中進行列表append操作

描述 給定一個數字列表,返回其所有可能的排列。 你可以假設沒有重複數字。 樣例 給出一個列表[1,2,3],其全排列為: [ [1,2,3], [1,3,2], [2,1,3]

排列做法

排列:從n個元素中任取m個元素,並按照一定的順序進行排列,稱為排列; 全排列:當n==m時,稱為全排列; 比如:集合{ 1,2,3}的全排列為: { 1 2 3}  { 1 3 2 }  { 2 1 3 }  { 2 3 1 }  { 3 2 1

排列演算法

一.                                 全排列演算法 首先:什麼是全排列=》百度一下 從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。 公式:全排列數

排列 歸求解+字典序 java 轉載

解決 nbsp 介紹 轉載 imp dict 問題 描述 clas 問題:給出一個字符串,輸出所有可能的排列。 全排列有多種算法,此處僅介紹常用的兩種:字典序法和遞歸法。 1、字典序法: 如何計算字符串的下一個排列了?來考慮"926520"這個字符串,我們從後向前找第一雙相

斐波那契數列迭代

int Fbi(int i)/*這裡Fbi就是函式自己,等於在呼叫自己*/ {  if(i<2)   return i==0?0:1;  return Fbi(i-1)+Fbi(i-2); } int main() {  int i;  int a[40];  printf("迭代顯示斐波那契數列:\

排列和非實現permutation(C++)

全排列問題 以下是C++程式碼實現: //Permutation1 和 permutation2 分別是基於遞迴和非遞迴的實現,都可以實現去除重複的排列 //讀者也可以自己提交之後到leet

楊輝三角的C語言實現

本文用C語言程式碼實現楊輝三角 遞迴演算法依據於f(m,n)=f(m-1,n)+f(m-1,n-1) 其中(m,n)為楊輝三角第m行第n個元素 演算法程式碼如下:   #include <stdio.h> //遞迴函式 int func(int m,in

連結串列翻轉的圖文講解迭代直接迴圈翻轉指標兩種實現【轉】

連結串列的翻轉是程式設計師面試中出現頻度最高的問題之一,常見的解決方法分為遞迴和迭代兩種。最近在複習的時候,發現網上的資料都只告訴了怎麼做,但是根本沒有好好介紹兩種方法的實現過程與原理。所以我覺得有必要好好的整理一篇博文,來幫忙大家一步步理解其中的實現細節。   我們知道

排列演算法實現

前言: 在一些演算法題當中有時需要進行全排列,是一個比較簡單的遞迴呼叫,在這裡記錄下,以後可以直接拿來使用。 過程: 例如{1,2,3,4,5}: 第一步: {1}和{2,3,4,5}的全排列組合; {2}和{1,3,4,5}的全排列組合; {3}和{2,1,4,5}的全排列組合; …

二叉樹後序遍歷演算法及C語言實現

二叉樹後序遍歷的實現思想是:從根節點出發,依次遍歷各節點的左右子樹,直到當前節點左右子樹遍歷完成後,才訪問該節點元素。 圖 1 二叉樹   如圖 1 中,對此二叉樹進行後序遍歷的操作過程為: 從根節點 1 開始,遍歷該節點的左子樹(以節點 2 為根節點); 遍歷節點 2 的左子樹(以節點 4 為根

二叉樹先序遍歷及C語言實現

二叉樹先序遍歷的實現思想是: 訪問根節點; 訪問當前節點的左子樹; 若當前節點無左子樹,則訪問當前節點的右子樹; 圖 1 二叉樹   以圖  1 為例,採用先序遍歷的思想遍歷該二叉樹的過程為: 訪問該二叉樹的根節點,找到 1; 訪問節點 1 的左子樹,找到節點 2; 訪問節點 2 的左子

排列的不同方式和STL演算法

#include<iostream> #include<cstdlib> #include<algorithm> #include<iomanip> #include<functional> #include<iterator>

歸併排序實現

摘要: (1)歸併排序幾乎以O(NlogN)的時間界實現,是典型的分治演算法; (2)歸併排序的基本思路很簡單:就是將目標序列分為兩個部分,將兩個子序列排序好之後,再將它們合併。注意到合併兩個已排序

JAVA實現二叉樹的前、中、後序遍歷

最近在面試中遇到過問到二叉樹後序遍歷非遞迴實現的方法,之前以為會遞迴的解決就OK,看來還是太心存僥倖,在下一次面試之前,特地整理一下這個問題。 首先二叉樹的結構定義,java程式碼如下: public class Node { private

快速排序 的原理及其java實現

快速排序由於排序效率在同為O(N*logN)的幾種排序方法中效率較高,因此經常被採用,再加上快速排序思想----分治法也確實實用,因此很多軟體公司的筆試面試,包括像騰訊,微軟等知名IT公司都喜歡考這個

C語言實現的求二叉樹的最大寬度版本

一、遞迴 這裡說的遞迴,並非是指整個函式遞迴,而是說其中一個子函式使用了遞迴。整個思路可以如下:要求取最大寬度,可以迴圈求取每一層的寬度,存入一個數組,然後在這個數組裡求最大值即可,陣列下標即層數(或高度)。對於求某一層的寬度,考慮把它寫成一個子函式,引數考慮起始結點以及對