思路
先排序,对于a0,a1,a2中 a0 == a1的情况,交换a0,a1得到的序列相同应该只保留一种,因此当a0先出现而a1紧跟着出现时,即存在a0…a1序列时进行剪枝,只保留a1…a0出现的序列。简单说就是相邻且相等的两个数,前数出现时后数不能跟着它一起出现
解法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10;
int n;
int a[N];
int st[N]; // 当前递归分支中的序列
bool use[N]; // 序列中的某一位是否被使用。use[1] = true 表示 a[1] 已经被使用
void dfs(int u)
{
if(u == n)
{
for(int i = 0; i < n; i++) printf("%d ", st[i]);
puts("");
return;
}
for(int i = 0; i < n; i++)
{
if(use[i]) continue;
if(i && a[i] == a[i-1] && use[i-1]) continue; // 同一递归分支 相邻两数相等 且 前面一个数用过了 第二个数再用会重复 剪枝
st[u] = a[i];
use[i] = true;
dfs(u+1);
st[u] = 0;
use[i] = false;
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
sort(a, a+n);
dfs(0);
return 0;
}
查看递归树分析递归过程
u
表示当前枚举的位(对于样例1 1 2, u的取值为0 1 2)
i
表示当前枚举的是序列中的哪个数。如i = 0是表示枚举 a[0]
,即第一个数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10;
int n;
int a[N];
int st[N];
bool use[N];
void dfs(int u)
{
if(u == n)
{
for(int i = 0; i < n; i++) printf("%d ", st[i]);
puts("");
return;
}
printf("u=%d位\n", u);
for(int i = 0; i < n; i++)
{
printf("枚举i=%d ", i);
if(use[i])
{
printf("i=%d用过了\n", i);
// puts("");
continue;
}
if(i && a[i] == a[i-1] && use[i-1]) // 同一递归分支 相邻两数相等 且 前面一个数用过了 第二个数再用会重复 剪枝
{
printf("i=%d剪枝\n", i);
// puts("");
continue;
}
st[u] = a[i];
printf("a[%d]=%d i=true\n", i, a[i]);
use[i] = true;
dfs(u+1);
st[u] = 0;
use[i] = false;
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
sort(a, a+n);
dfs(0);
return 0;
}