2月19日,多云。“小楼一夜听春雨,深巷明朝卖杏花“。
例1:输入一个数n,按字典序从小到大的顺序输出1~n的全排列。两个序列的字典序大小关系等价于从开始的第一个不相同位置处的大小关系。例如,(1,3,2) < (2,1,3)
当n = 3时,所有排序的排序结果是(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1)。
俺老猪擅长穷举法:寻找问题解的一种可靠的方法是首先列出所有可能候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解。理论上,当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时,上述方法是可行的。不过在实际应用中,很少使用这种方法,因为候选解的数量通常都非常大,即便采用最快的计算机也只能解决规模很小的问题。
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
for(a=1; a<=3; a++)
for(b=1; b<=3; b++)
for(c=1; c<=3; c++)
if((a!=b)&&(a!=c)&&(b!=c))
cout<<a<<" "<<b<<" "<<c<<endl;
return 0;
}
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
从问题的某一种可能出发,搜索从这种情况出发所能达到的所有可能, 当这一条路走到“ 尽头 ”而没达到目的地的时候, 再倒回上一个出发点, 从另一个可能出发, 继续搜索. 这种不断“倒回 一步"寻找解的方法, 称作" 回溯法 "。
为师给出算法框架,悟空,还是你来实现以下。
1.
procedure
dfs
(
step:integer
)
2.
begin
3.
if
到达边界状态
then
输出解
;
4.
else for
i
:= 1 to n do //
顺次尝试每一种可能
5.
begin
6.
if
满足条件
then
7.
begin
8.
保存结果
;
9.
dfs
(step+1);
10.
恢复:保存结果之前的状态
11.
end;
12.
end;
13.
end;
14.
Begin
15.
dfs
(1);
16.
end.
师傅,让俺老孙试一试吧。
2
1 2
2 1
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
俺沙悟净也试一试
俺白龙马也试一试
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
int a[20];
bool used[20];
int n;
void print()
{
for(int i=1; i<=n; i++)
cout<<a[i]<<" " ;
cout<<endl;
}
void dfs(int step)
{
if (step ==(n + 1))
print();
else
{
for(int i=1; i<=n; i++)
{
if (used[i] == false)
{
a[step] = i;
used[i] = true;
dfs(step+1);
used[i] = false;
}
}
}
}
int main()
{
memset(used, false, sizeof(used));
while(scanf("%d", &n) == 1)
{
dfs(1);
cout<<endl;
}
return 0;
}
结果:
2
1 2
2 1
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
大家都知道,深度优先的主要思想就是“不撞南墙不回头”,“一条路走到黑”,如果遇到“墙”或者“无路可走”时再去走下一条路。所以先规定好一个走路的规则,比如就按照右下左上顺时针的方式去尝试。
HDU 1016 Prime Ring Problem是一道简单的搜索题,简单说就是一位一位去试,一位一位地填上数字,看是否满足条件,具体看注释。#include <cstring>
#include <cstdio>
using namespace std;
// 素数表,数据较小直接打表也可以
bool prime[41];
void init()
{
memset(prime, true, sizeof(prime));
prime[0] = prime[1] = false;
for(int i=2; i<=40; i++)
{
if(prime[i])
{
for(int j=i*2; j<=40; j+=i)
prime[j] = false;
}
}
}
// 标记
bool vis[21];
int num[21];
int N, t=1;
void dfs(int n)
{
if(n == N && prime[1+num[n]])
{
// 判断最后一位是否满足条件,打印
printf("1");
for(int i=2; i<=N; i++)
printf(" %d", num[i]);
printf("\n");
}
else
{
// 在还未访问的数据中选择满足条件的,标记并访问
for(int i=2; i<=N; i++)
{
if(!vis[i] && prime[i+num[n]])
{
num[n+1] = i;
vis[i] = true;
dfs(n+1);
// 访问结束,重新设为未访问
vis[i] = false;
}
}
}
}
int main()
{
init();
memset(vis, false, sizeof(vis));
vis[1] = true;
num[1] = 1;
while(scanf("%d", &N) == 1)
{
printf("Case %d:\n", t++);
dfs(1);
printf("\n");
}
return 0;
}
#include<iostream>
using namespace std;
int P[38]= {0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1};
// 素数表,数据较小直接打表
int visited[21];
int a[21];
int n;
void DFS(int count)
{
int i;
if(count==n&&P[a[count-1]+1]==1)// // 判断最后一位是否满足条件,打印
{
cout<<a[0];
for( i=1; i<n; i++)
{
cout<<' '<<a[i];
}
cout<<endl;
}
else
{
for(i=2; i<=n; i++)
{
if(!visited[i]&&P[a[count-1]+i]==1)//在还未访问的数据中选择满足条件的,标记并访问
{
a[count]=i;
visited[i]=1;
DFS(count+1);
visited[i]=0; // 访问结束,重新设为未访问
}
}
}
}
int main()
{
a[0]=1;
int A=1;
while(cin>>n)
{
cout<<"Case "<<A++<<':'<<endl;
DFS(1);
cout<<endl;
}
return 0;
}