回溯求解排列组合的关键在于两点:
一是要明白回溯的思想到底是什么
二是要考虑清楚什么时候进行向下探索,什么时候碰壁回头,什么时候到达回溯的重点,退出循环。也就是回溯过程中的约束条件
回溯思想:向前走,碰壁回头
回溯的一般形式如下:
以求解排列A(n,m)为例,这里解释一下排列的约束条件:
1.第一个约束条件就是选出的数不一样。
2.每一个数都小于等于n。
3.选够m个数即进行输出。
4.向下探索,向上回溯。
至于组合,只需要在排列的第一个条件上加上一个固有的顺序要求就o了。
运行截图:
源码这里暂时不予给出,有需要的话,可以评论区留下自己的邮箱。(因为是作业,害怕自己出现类同代码。)
预计11月底,进行给出。
二更:
源码附上:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
//求解A(n,m);
void PaiLie(int m,int n); //排列
void ZuHe(int m,int n); //组合
int main()
{
int m,n;
cout<<"Input n m:";
cin>>n>>m;
PaiLie(n,m);
ZuHe(n,m);
}
void PaiLie(int m,int n) //排列 A(m,n)
{
int a[100]={0};
int i=1;
int count=0; //计算总长度
a[i]=1;
while(1)
{
int flag=1;
for(int j=1;j<i;j++)
{
if(a[i]==a[j]) //不满足约束条件,标志位置零
{
flag=0;
break;
}
}
if(flag&&i<n) //向下探索
{
i++;
a[i]=1;
continue;
}
if(flag&&i==n) //满足条件进行输出
{
for(int j=1;j<=n;j++)
{
if(j<n)
{
cout<<a[j]<<",";
}
if(j==n)
{
cout<<a[j]<<endl;
}
}
count++;
}
while(a[i]==m&&i>1) //向上回溯
{
i--;
}
if(i==1&&a[i]==m) //回溯到头了,退出循环
{
break;
}
else //本阶段继续探索
{
a[i]++;
}
}
cout<<"回溯 排列个数:"<<count<<endl;
}
void ZuHe(int m,int n) //组合
{
int a[100]={0};
int i=1;
int count=0;
a[i]=1;
while(1)
{
int flag=1;
for(int j=1;j<i;j++)
{
if(a[i]>=a[j]) //不满足约束条件,标志位清零
{
flag=0;
break;
}
}
if(flag&&i<n) //数量不够,继续向下探索
{
i++;
a[i]=1;
continue;
}
if(flag&&i==n) //满足条件,进行输出
{
for(int j=1;j<=n;j++)
{
if(j<n)
{
cout<<a[j]<<",";
}
if(j==n)
{
cout<<a[j]<<endl;
}
}
count++;
}
while(a[i]==m&&i>1) //向上回溯
{
i--;
}
if(a[i]==m&&i==1) //回溯到头,退出回溯
{
break;
}
else
{
a[i]++; //在当前阶段继续回溯
}
}
cout<<"回溯 组合个数:"<<count<<endl;
}