全排列(递归与函数实现)

例题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1027

 

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));
	}
}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值