回溯算法 全排列3种实现含next_permutation

1 回溯算法原理

 回溯法也就是我们所说的dfs,可以系统地搜索一个问题的所有解或任意解。基本的含义是按照深度优先的策略,从根节点出发寻找解空间,在到达最底端时进行回溯并判断,继续向下搜索。
一般回溯法可以画一个完全二叉树就可以形象的表示。
在这里插入图片描述
回溯算法一般以递归实现,有模板如下:

void dfs(int cur)
{
  if(到达出口){
       输出解;//result.add(路径)->如果不要求打印要求返回
       return;
  }
  for(int i=0 ;i<方案数; i++)//选择列表
  {
    if(方案可行){
       做选择//这里一般都是借用一个vis数组记录下标是否已被选择
       dfs(cur+1);
       撤销选择//回溯的基本
    }
  }
}

2 next_permutation

在进行全排列时,我们可以方便的调用系统函数next_permutation进行实现。
  next_permutation(first,last)
  将[first,last]范围内的元素重新排列为下一个按字典顺序更大的排列中。这里字典序就是从小到大进行排序。
例如: 1 2 3 的下一个字典序为 1 3 2 下一个字典序为 2 1 3 ,2 3 1 …
成功返回true,失败(也就是说已经是最大了 如3 2 1 )则返回false

3 全排列的三种实现

给定一个没有重复数字的序列,返回其所有可能的全排列。
第一种方法:调用系统函数next_permutation(first,last)
这里要注意一点是,我们不知道给的序列是否排好序,因为next_permutation(first,last) 是按字典序的,所以之前必须先用sort进行排序

//要求打印
void permutation(vector<int>& ar)
{
 sort(ar.begin(), ar.end());
 do {
      for (int i = 0; i <ar.size();i++ )
      cout << ar[i] << " ";
      cout << endl;
 } while (next_permutation(ar.begin(), ar.end()));
}

//要求返回
 vector<vector<int>> permutation(vector<int>& ar)
{
   sort(ar.begin(), ar.end());
   vector<vector<int>> ans;
   do {
         ans.push_back(ar);
} while (next_permutation(ar.begin(), ar.end()));
  return ans;
}

第二种方法: 递归实现
我们发现 1 2 3 全排列是
1 2 3, 1 3 2
2 1 3 , 2 3 1
3 1 2 , 3 2 1
要么1开头,剩下的做全排列,要么2开头(swap(1,2)),剩下的做全排列,要么3开头(swap(1,3),剩下的做全排列。明显就是一个递归

void Recpermutation(vector<int>& ar,int p,int q)
{
 if (p == q)   //打印
 {
  for (int i = 0; i < ar.size(); i++)
   cout << ar[i] << " ";
  cout << endl;
 }
 else
fo(int i=p ; i<= q; p++)
 {
  std::swap(ar[i], ar[p]);//先交换
  Recpermutation(ar, p + 1, q);
  std::swap(ar[i], ar[p]);//在交换回来进行下一次递归(2开头)
 }
}
int main()
{
 vector<int> ar = {1,2,3,4};
 Recpermutation(ar,0,3); 
}

第三种方案,dfs,所以需要一个vis[n]数组记录选择,已经选的=1,否则为0

vector<int> vis;
vector<int> nu;
vector<int> ret;
vector<vector<int>> ans;
int n;
void dfs(int cur)
{
 if (cur == n)
 {
   ans.push_back(ret);
   return;
 }
 for (int i = 0; i < n; i++)
 {
  if (vis[i] == 0) {
   vis[i] = 1;//开始选择
   ret[cur] = nu[i];//记录已经做的选择
   dfs(cur + 1);//递归
   vis[i] = 0;//撤销选择
  }
 }
}
vector<vector<int>> Dfspermutation(vector<int>& ar)//深度优先遍历
{
 n = ar.size();
 vis.assign(n, 0);
 ret.assign(n, 0);
 nu = ar;
 dfs(0);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值