欢迎同学们查看https://blog.csdn.net/2301_80065984/category_12688940.html (算法专栏)其他文章
目录
【搜索与回溯算法】组合的输出
题目描述
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r<=n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
例如n=5,r=3,所有组合为:
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
输入
一行两个自然数n、r(1<n<21,1<=r<=n)。
输出
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素之间用空格隔开,所有的组合也按字典顺序。
样例输入
5 3
样例输出
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
题解
我们只需要将其每一位都暴力枚举即可,注意需要使用vis数组检测这个数字是否用过
代码见下:
#include<bits/stdc++.h>
using namespace std;
int n,r;
int a[30],vis[30];
void dfs(int x,int y)//搜索函数
{
if(x>r)
{
for(int i=1;i<=r;i++)
{
printf("%d ",a[i]);
}
printf("\n");
return;
}
for(int i=1;i<=n;i++)//每种情况都试一遍
{
if(vis[i]==0&&i>a[x-1])//判断可行性
{
a[x]=i;
vis[i]=1;
dfs(x+1,r);//搜索
vis[i]=0;//回溯
}
}
}
int main()
{
scanf("%d%d",&n,&r);
dfs(1,r);//调用函数
return 0;
}
【搜索与回溯算法】装载问题
题目描述
有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。
输入
第一行有2个正整数n和c。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。
输出
将计算出的最大装载重量输出
样例输入
5 10 7 2 6 5 4
样例输出
10
数据范围限制
n<=35,c<=1000
题解
我们只需要将每个集装箱都进行尝试要和不要这两种处理,也就是枚举,最后进行对比找出最优解
(其实搜索就是暴力枚举)
话不多说,代码如下:
#include<bits/stdc++.h>
using namespace std;
int n/*集装箱*/,c/*总载重*/,ans=0;
int a[30];
void dfs(int x,int y/*目前最优解*/)
{
if(x>n)//边界
{
if(ans<y)
{
ans=y;
}
return;
}
if(y+a[x]<=c)//其中一种情况尝试
{
dfs(x+1,y+a[x]);
}
dfs(x+1,y);//另一种情况尝试
}
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1,0);
printf("%d",ans);
return 0;
}
【搜索与回溯算法】迷宫问题
接下来便是搜索与回溯算法最重要的一个点:迷宫问题!!!
题目描述
设有一个N*N(2<=N<10)方格的迷宫,入口和出口分别在左上角和右上角.迷宫格子中分别放0和1,0表示可通过,1表示不能通过,入口和出口处肯定是0.迷宫走的规则如下所示:即从某点开始,有八个方向可走,前进方格中数字和为0时表示可通过,为1时表示不可通过,要另找路径.找出所有从入口(左上角)到出口(右上角)的路径(不能重复),输出路径总数,如果无法到达,则输出0.
输入
第一行输入n,表示n行n列的迷宫
接下来有n行,每行n个数,分别用1或0表示能否通过
输出
输出路径数
样例输入
3 0 0 0 0 1 1 1 0 0
样例输出
2
题解
我们仅需将每一步都试一遍,只要符合要求即可走出去
代码如下:
#include<bits/stdc++.h>
using namespace std;
int dx[8]={0,0,-1,1,-1,-1,1,1};//x坐标增量
int dy[8]={1,-1,0,0,1,-1,1,-1};//y坐标增量
int ans,n,maz[1000][1000];
void dfs(int x,int y)
{
if(x==0&&y==n-1)
{
ans++;
return;
}
for(int i=0;i<8;i++)//每个方向都要试一遍
{
int xx=x+dx[i];//我们亲切地称其为“替死鬼”
int yy=y+dy[i];//我们亲切地称其为“替死鬼”
if(xx>=0&&yy>=0&&xx<n&&yy<n && maz[xx][yy]==0)//判断替死鬼走的这一步有没有障碍或走出边界
{
maz[x][y]=1;//没有问题就走出去
dfs(xx,yy);
maz[x][y]=0;//回溯
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&maz[i][j]);//输入
}
}
dfs(0,0);
printf("%d",ans);
return 0;
}
【搜索与回溯算法】马的走法
题目描述
在5X5的棋盘上,给定一位置,输出马回到原点有多少种不同的方案。
注意:马走的每一步必须在棋盘上,走斜日,如下图:
输入
给定一位置,x ,y,中间有一空格隔开。
输出
输出可以回到原点的方案总数
样例输入
1 1
样例输出
61424
题解
相对于上一题,我们仅需对方向增量进行改变,因为马是走日的
代码如下:
#include<bits/stdc++.h>
using namespace std;
int sum=0,a,b,c=0;
int maz[10][10];
int dx[8]={-2,-2,-1,1,2,2,1,-1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
void dfs(int x,int y)
{
if(x==a&&y==b&&c==1)
{
sum++;
return;
}
c=1;
for(int i=0;i<8;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<=5&&yy<=5&&xx>=1&&yy>=1 && maz[xx][yy]==0)
{
maz[xx][yy]=1;
dfs(xx,yy);
maz[xx][yy]=0;
}
}
}
int main()
{
scanf("%d%d",&a,&b);
dfs(a,b);
printf("%d",sum);
return 0;
}
结尾
本章结束了,搜索与回溯算法还是需要熟悉一段时间的,小编会再发布一篇巩固文。
记得点赞关注加收藏,欢迎在下方评论提出问题,小编会耐心解答!