- 实验预习报告
一、实验内容
对需要使用回溯法的问题进行理解和分析,学会使用一定的回溯算法解决问题。并分析利用回溯法解决的一些常见模型。
二、简述实验思想及相关内容
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
实际上是一种试探算法,这种算法跟暴力搜索最大的不同在于,在回溯算法里,是一步一步地小心翼翼地进行向前试探,会对每一步探测到的情况进行评估,如果当前的情况已经无法满足要求,那么就没有必要继续进行下去,也就是说,它可以帮助我们避免走很多的弯路。
回溯算法的特点在于,当出现非法的情况时,算法可以回退到之前的情景,可以是返回一步,有时候甚至可以返回多步,然后再去尝试别的路径和办法。这也就意味着,想要采用回溯算法,就必须保证,每次都有多种尝试的可能。
三、设计要点
1.回溯算法强调了回退操作对于搜索的合理性,而深度优先遍历强调的是一种遍历的思想。回溯法要解决的问题都是在集合中递归地查找子集合,所以都可以抽象为树形结构的问题。
2.回溯算法解决问题的过程中创建的状态树并不都是满二叉树,因为在试探的过程中,有时会发现此种情况下,再往下进行没有意义,所以会放弃这条死路,回溯到上一步。在树中的体现,就是在树的最后一层不是满的,即不是满二叉树,需自己判断哪些叶子结点代表的是正确的结果。
四、算法初步分析
通过查阅资料,初步分析了回溯法的效率。时间通常取决于状态空间树上实际生成的那部分问题状态的数目。但是回溯法对于不同的实例,在计算时间上有很大的差异。经验表明,在很多的情况下,对于具有大n值的实例,回溯算法的确可在很短的时间内求得其解,因此回溯法不失为一种有效的算法设计策略。
五、预习小结
本次实验,做了大量的回溯法问题,难度很大,思路很复杂,要求对回溯思想的理解得很深,提高了我对算法学习对要求,以后还要继续学习这些算法,更深刻的理解,帮助更快的解决问题。
回溯算法实验
- 实验目的
1.掌握回溯算法的基本概念;
2.熟练掌握回溯算法解决问题的基本步骤;
3.通过实验题目的理解并编程实现,掌握回溯法的算法框架;
4.学会利用回溯算法解决实际问题。
- 可行性分析
回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
1.回溯法适用:有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法。
2.有组织的穷举式搜索:回溯法的基本做法是搜索或者有的组织穷尽搜索。它能避免搜索所有的可能性。即避免不必要的搜索。这种方法适用于解一些组合数相当大的问题。
3.搜索解空间树:回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
- 方案设计
一、所需知识点
用回溯算法解决问题的一般步骤:
1.针对所给问题,定义问题的解空间,它至少包含问题的一个解。
2.确定易于搜索的解空间,使能用回溯法方便地搜索整个解空间 。
3.以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。这个开始结点就成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。
二、数学模型
采用动态规划、回溯搜索、分治算法、分支定界的数学模型。针对参照某种事物系统的特征或数量依存关系,采用数学语言,概括地或近似地表述出的一种数学结构,这种数学结构是借助于数学符号刻划出来的某种系统的纯关系结构。从广义理解,数学模型包括数学中的各种概念,各种公式和各种理论。从狭义理解,数学模型只指那些反映了特定问题或特定的具体事物系统的数学关系结构,这个意义上也可理解为联系一个系统中各变量间内的关系的数学表达。
三、详细方法
使用回溯法解决问题的过程,实际上是建立一棵“状态树”的过程。随着问题规模的增加,往往所有算法的时间耗费都呈现上升趋势。所以在进行测试实验时,对问题规模进行一定比例的增长,得出算法在运行时所消耗的时间,根据时间来确定算法的时间耗费能力,可以在之后的耗时特点中进行相应的数据记录,以此来进行数据分析和比较。
- 代码设计与开发
在不超过实验所要求的数据规模中,根据回溯算法的特点,对数据规模进行不断的扩大,按照具体的实验内容对数据进行不同程度改变,将改变后的数据经由固定的格式将其输入到程序中,根据程序运行所消耗的时间对时间消耗进行判断。
对其数据大小也进行一定的规划,由小至大到大小结合,对算法处理数据的能力进行测试,将其由于上述耗时性能进行总和判断,对算法性能能够有一定的理解分析和比较的帮助。
1.小辉辉玩积木
代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
int n;
long long int a[60];
int main() {
for (int i = 1; i <= 50; i++) {
if (i == 1)
a[i] = 1;
else if (i == 2)
a[i] = 2;
else
a[i] = a[i - 1] + a[i - 2];
}
while(cin>>n){
cout<<a[n]<<endl;
}
}
2..入侵和反击
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int a[maxn],dp[maxn];
int b[maxn];
int main()
{
int t,n,i;
cin>>t;
while(t--)
{
cin>>n;
for(i=0;i<n;i++) cin>>a[i];
memset(b,0,sizeof(0));
for(i=0;i<n;i++)
{
b[n-1-i]=a[i];
}
memset(dp,0,sizeof(0));
dp[0]=b[0];
int pos,sum=1;
for(i=1;i<n;i++)
{
pos=lower_bound(dp,dp+sum,b[i]+1)-dp;
dp[pos]=b[i];
sum=max(sum,pos+1);
}
cout<<n-sum<<endl;
}
return 0;
}
3..反恐精英渣渣辉
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int n,m;
int a[maxn],b[maxn];
int dp[maxn][maxn];
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
for(int j=1;j<=m;j++)
scanf("%d",&b[j]);
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
printf("%d\n",dp[m][m]);
}
return 0;
}
4.爱旅游的女朋友
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int c[maxn];
int w[maxn];
bool x[maxn];
int main()
{
int v,n;
while(scanf("%d %d",&v,&n) != EOF){
int p = 1;
int a,b,t;
for(int i = 1;i <= n; i++){
scanf("%d",&a);
x[p] = false;
c[p] = a,
p++;
}
p=1;
for(int i = 1;i <= n; i++){
scanf("%d",&b);
w[p] = b;
p++;
}
p--;
for(int i = 0;i < n; i++){
dp[i][0] = dp[0][i] = 0;
}
for(int i = 1;i <= p; i++){
for(int j = 1;j <= v; j++){
if(j < c[i]){
dp[i][j] = dp[i - 1][j];
}else{
if(x[i] == true)
dp[i][j] = max(dp[i - 1][j],dp[i][j - c[i]] + w[i]);
else
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - c[i]] + w[i]);
}
}
}
printf("%d\n",dp[p][v]);
}
return 0;
}
5.渣渣辉的蜜月
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int c[maxn];
int w[maxn];
bool x[maxn];
int main()
{
int v,n;
while(scanf("%d %d",&v,&n) != EOF){
int p = 1;
int a,b,t;
for(int i = 1;i <= n; i++){
scanf("%d",&a);
x[p] = true;
c[p] = a,
p++;
}
p=1;
for(int i = 1;i <= n; i++){
scanf("%d",&b);
w[p] = b;
p++;
}
p--;
for(int i = 0;i < n; i++){
dp[i][0] = dp[0][i] = 0;
}
for(int i = 1;i <= p; i++){
for(int j = 1;j <= v; j++){
if(j < c[i]){
dp[i][j] = dp[i - 1][j];
}else{
if(x[i] == true)
dp[i][j] = max(dp[i - 1][j],dp[i][j - c[i]] + w[i]);
else
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - c[i]] + w[i]);
}
}
}
printf("%d\n",dp[p][v]);
}
return 0;
}
6.好男人的菜市场之旅
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int c[maxn];
int w[maxn];
bool x[maxn];
int main()
{
int v,n;
int snum;
scanf("%d",&snum);
while(snum--){
int p = 1;
int a,b,t;
scanf("%d %d",&v,&n);
for(int i = 1;i <= n; i++){
scanf("%d %d %d",&a,&b,&t);
x[p] = false;
while(t--){
c[p] = a,w[p] = b;
p++;
}
}
p--;
for(int i = 0;i < n; i++){
dp[i][0] = dp[0][i] = 0;
}
for(int i = 1;i <= p; i++){
for(int j = 1;j <= v; j++){
if(j < c[i]){
dp[i][j] = dp[i - 1][j];
}else{
if(x[i] == true)
dp[i][j] = max(dp[i - 1][j],dp[i][j - c[i]] + w[i]);
else
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - c[i]] + w[i]);
}
}
}
printf("%d\n",dp[p][v]);
}
return 0;
}
7.跳跃的渣渣辉
代码:
#include<stdio.h>
int nums[110];
int n;
int jump(int nums[]) {
int i=0;
int res = 0;
while(i<n-1){
int steps = nums[i];
if(steps>=n-1-i){
res++;
break;
}
int max = nums[i+1];
int index = i+1;
for(int j=index; j<=i+steps && j<n-1; j++){
if(nums[j]+j-index >= max){
max = nums[j];
index = j;
}
}
res++;
i = index;
}
return res;
}
int main() {
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
scanf("%d",&nums[i]);
}
int ans = jump(nums);
printf("%d\n",ans);
}
}
8.创客更新装备
代码:
#include<iostream>
#include<cstdio>
using namespace std;
#define INF 0x3fffffff
const int maxn = 1005;
int t[maxn];
int dp[4][maxn];
int main()
{
int n;
while(scanf("%d",&n) != EOF){
for(int i = 0;i < 4; i++){
fill(dp[i],dp[i] + maxn, INF);
}
for(int i = 1;i <= n; i++){
scanf("%d",&t[i]);
}
for(int i = 1;i <= n; i++){
scanf("%d",&dp[0][i]);
}
for(int i = 0;i < 3; i++){
for(int j = i;j <= n; j++){
for(int k = 1;k <= j; k++){
if(t[j] > t[k])
dp[i][j] = min(dp[i][j],dp[i - 1][k] + dp[0][j]);
}
}
}
int Min = INF;
for(int i = 3;i <= n; i++){
Min = min(Min,dp[2][i]);
}
if(Min == INF) printf("-1\n");
else printf("%d\n",Min);
}
return 0;
}
9.最小拦截系统
代码:
#include<stdio.h>
#include<iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
while(cin >> n)
{
int a[30000];
int i,j;
for(i = 0; i < n ; i++)
{
cin >> a[i];
}
int b[3000];
b[0] = 1;
int t;
for(i = 1; i < n; i++)
{
t = 0;
for(j = 0; j < i; j++)
{
if(a[i] > a[j])
{
if(t <= b[j])
t = b[j];
}
}
b[i] = t + 1;
}
int mm = b[0];
for(i = 1; i < n; i++)
{
if(b[i] > mm)
mm = b[i];
}
cout << mm << endl;
}
return 0;
}
10.让人头疼的双十一
代码:
#include <iostream>
#include <stdio.h>
using namespace std;
int dp[300100];
int main()
{
int T,n,m;
while(cin>>T)
{
for(int k=1;k<=T;k++)
{
fill(dp,dp+300100,0);
cin>>n>>m;
int a[m],b[m];
for(int i=0;i<m;i++)
cin>>a[i];
for(int i=0;i<m;i++)
cin>>b[i];
for(int i=0;i<m;i++)
{
for(int j=n;j>=a[i];j--)
dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
}
printf("Case #%d: %d\n",k,dp[n]);
}
}
return 0;
}
11.简单的一道题
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int c[maxn];
int w[maxn];
bool x[maxn];
int main()
{
int v,n;
while(scanf("%d %d",&v,&n) != EOF){
int p = 1;
int a,b,t;
for(int i = 1;i <= n; i++){
scanf("%d %d %d",&a,&b,&t);
if(t == 0){
x[p] = true;
c[p] = a;w[p] = b;
p++;
}else{
x[p] = false;
while(t--){
c[p] = a,w[p] = b;
p++;
}
}
}
p--;
for(int i = 0;i < n; i++){
dp[i][0] = dp[0][i] = 0;
}
for(int i = 1;i <= p; i++){
for(int j = 1;j <= v; j++){
if(j < c[i]){
dp[i][j] = dp[i - 1][j];
}else{
if(x[i] == true)
dp[i][j] = max(dp[i - 1][j],dp[i][j - c[i]] + w[i]);
else
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - c[i]] + w[i]);
}
}
}
printf("%d\n",dp[p][v]);
}
return 0;
}
- 实验结果展示
1.小辉辉玩积木
2.入侵和反击
3.反恐精英渣渣辉
4.爱旅游的女朋友
5.渣渣辉的蜜月
6.好男人的菜市场之旅
7.跳跃的渣渣辉
8.创客更新装备
9.最小拦截系统
10.让人头疼的双十一
11.简单的一道题
- 终身学习
这个领域很前沿的知识,这个可以去相关杂志网站去仔细查找,如通过知网进行文献查找和分析,了解相关领域的前沿信息和发展方向。一些外文书籍也可以很好的帮助我学习最前沿的算法知识,所以眼界要更加开阔,搜集更多的算法信息。