全排列问题(函数next_permutation和搜索prev_permutation)

组合数学中会对一组数据或字母进行全排列,下面介绍两种解决方案:

1.函数next_permutation:这是一个求一个排序的下一个排列的函数,可以遍历全排列,要包含头文件<算法>,

与之完全相反的函数还有prev_permutation:(与next_permutation排列顺序相反,next从序列最小数开始,prev从最大数开始)

具体请看: http://www.cplusplus.com/reference/algorithm/prev_permutation/

(1)int型

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
 int a[3]={1,2,3};
 do
 {
   cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<endl;
 } while (next_permutation(a,a+3));
 return 0;
}

PS:在使用next_premutation()前需要进行升序排列,否则会出现减少排列的结果。

输出:
 
 1 2 3
 1 3 2
 2 1 3
 2 3 1
 3 1 2
 3 2 1

如果改成while(next_permutation(a,a + 2));
则输出:
 1 2 3
 2 1 3

只对前两个元素进行字典排序
显然,如果改成while(next_permutation(a,a + 1)); 则只输出:1 2 3

若排列本来就是最大的了没有后继,则next_permutation执行后,会对排列进行字典升序排序,相当于循环

int list[3]={3,2,1};
next_permutation(list,list+3);
cout<<list[0]<<" "<<list[1]<<" "<<list[2]<<endl;
 
//输出: 1 2 3

(2)焦炭型

扫描二维码关注公众号,回复: 2463308 查看本文章
int main()
{
 char ch[205];
cin >> ch;
 
sort(ch, ch + strlen(ch) );

输入:2013456987;

输出:0123456789;

 char *first = ch;
 char *last = ch + strlen(ch);
 int main(){
 do {
    cout<< ch << endl;
    }while(next_permutation(first, last));
    return 0;
}

这样我们就不需要知道字符串的大小了

(3)string类型

int main()
{
 string line;
 while(cin>>line&&line!="#")
{
 if(next_permutation(line.begin(),line.end())) //从当前输入位置开始
cout<<line<<endl;
 else cout<<"No\n";
}
}
 
 
 
int main()
{
 string line;
 while(cin>>line&&line!="#")
{
sort(line.begin(),line.end());//全排列
cout<<line<<endl;
 while(next_permutation(line.begin(),line.end()))
cout<<line<<endl;
}
}

 next_permutation自定义比较函数


#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int cmp(char a,char b) //'A'<'a'<'B'<'b'<...<'Z'<'z'.
{
 if(tolower(a)!=tolower(b))
 return tolower(a)<tolower(b);
 else
 return a<b;
}
int main()
{
 char ch[20];
 int n;
cin>>n;
 while(n--)
{
scanf("%s",ch);
sort(ch,ch+strlen(ch),cmp);
 do
{
printf("%s\n",ch);
}while(next_permutation(ch,ch+strlen(ch),cmp));
}
 return 0;
}

 2.回溯(DFS搜索)

代码如下:

/*
*  writer:Demo(codevs)
*  time:2018.7.29
*/
#include<iostream>
using namespace std;
bool mark[20];
int a[20],n;
void dfs(int x)
{
	if(n+1==x)
	{
		for(int i=1;i<=n;i++)
		{
			cout<<a[i]<<" ";
		}
		cout<<"\n";
		return;
	}
	else
	{ 
 		for(int i=1;i<=n;i++)
		{
			if(!mark[i])
			{
				a[x]=i;
				mark[i]=true;
				dfs(x+1);
				mark[i]=false;
			}
		}
	}
}
int main()
{
	cin>>n;
	dfs(1);
	return 0; 
} 

还有一种写法模仿next_permutation();

代码如下:

#include <iostream>
using namespace std;
void swap(int &a,int &b)//交换两个元素
{
    int tem;
    tem = a;
    a = b;
    b = tem;
}
int sum=0;
void cal(int *a,int first,int end)
{
    if(first == end)//如果递归到深层时,到最后交换的元素即时最后一个元素时就打印出来
    {
        sum++;
        for(int i = 0; i <= end; i++)
        cout<<a[i]<<" ";
        cout<<endl;
    }
    else
    {
        for(int i = first; i <= end; i++)
        {//循环遍历使得当前位置后边的每一个元素都和当前深度的第一个元素交换一次
            swap(a[first],a[i]);//使得与第一个元素交换
            cal(a,first+1,end);//深入递归,此时已确定前边的元素,处理后边子序列的全排列形式。
            swap(a[first],a[i]);//恢复交换之前的状态
        }
    }
}
int main()
{ 
    int a[4] = {1,2,3,4};
    cal(a,0,3);
    cout<<"一共"<<sum<<"种排列";
    system("pause");
    return 0;
}

喜欢就点个赞呗!

猜你喜欢

转载自blog.csdn.net/xyqqwer/article/details/81273813