ACM知识点总结 -【搜索技术】
本系列适用于有些基础的同学食用,因为我个人感觉那些大佬写的文章太深奥了,每个人有每个人的代码风格,还是自己写出来的代码自己看着舒服,所以我就开始写ACM知识点部分,后面会有习题及其讲解,基础的概念在本系列文章中不做过多赘述,希望大家能够理解。本系列会持续更新,希望大家多多关注。
目录
1.1递归和排列
(1)用STL输出全排列
(2)用递归求全排列
1.2子集生成和组合问题
1.3 BFS
1.4八数码问题与状态图搜索
1.5 BFS与A*算法
1.6 双向广搜
1.7 DFS
1.8 IDA*
1.1递归和排列
由于性能问题,全排列采用4个数字
(1)用STL输出全排列
//用STL输出全排列
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(register int i=x;i<=y;i++)
int main(){int data[10]={1,5,6,8,7,9,3,2,4};sort(data,data+4);//前n个数的全排列,按照字典序 do{fo(i,0,3) cout<<data[i]<<" ";cout<<endl;}while(next_permutation(data,data+4));return 0;
}
(2)用递归求全排列
#include<bits/stdc++.h>
using namespace std;
#define Swap(a,b) {int temp=a;a=b;b=temp;}
#define fo(i,a,b) for( int i=a;i<=b;i++)
int data[4]={4,2,1,3};
int num=0;void pri_a(){fo(i,0,3) cout<<data[i]<<" ";cout<<endl;
}
int Perm(int begin,int end){if(begin==end){pri_a();num++;}else{for(int i=begin;i<=end;i++){Swap(data[begin],data[i]);Perm(begin+1,end);Swap(data[begin],data[i]); }}
}
int main(){clock_t be,en;be=clock();sort(data,data+4);Perm(0,3);en=clock();cout<<(double)(en-be)/1000<<endl;cout<<num;return 0;
}
运行结果如下:
注:上述代码中添加了一个测试运行时间的函数
1.2子集生成和组合问题
如何求n个数的子集?
#include<bits/stdc++.h>
#define fo(i,a,b) for( int i=a;i<=b;i++)
using namespace std;
void p(int n){for(int i=0;i<(1<<n);i++){fo(j,0,n-1){if(i&(1<<j)){cout<<j<<" ";}}cout<<endl;}
}
int main(){int n;cin>>n;p(n);return 0;
}
如何打印n个数中任意m个数的组合?
#include<bits/stdc++.h>
#define fo(i,a,b) for( int i=a;i<=b;i++)
using namespace std;
void p(int n,int m){fo(i,0,(1<<n)-1){int num=0,kk=i;while(kk){kk=kk&(kk-1);num++;}if(num==m){fo(j,0,n-1){if(i&(1<<j)) cout<<j<<" ";}cout<<endl;}}
}
int main(){int n,m;cin>>n>>m;p(n,m);return 0;
}
1.3 BFS
以杭电oj的一个习题引入→题目传送门
#include<iostream>
#include<queue>
#define fo(i,a,b) for( int i=a;i<=b;i++)
using namespace std;
char room[23][23];
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int n,m,num;
#define check(x,y) (x<n && x>=0 && y>=0 && y<m)
struct node{int x,y;
};
void bfs(int bx,int by){num=1;queue<node>q;node stare;stare.x=bx;stare.y=by;q.push(stare);while(!q.empty()){stare=q.front();q.pop();fo(i,0,3){node temp;temp.x=stare.x+dir[i][0];temp.y=stare.y+dir[i][1];if(check(temp.x,temp.y) && room[temp.x][temp.y]=='.'){room[temp.x][temp.y]='#';num++;q.push(temp);}}}
}
int main(){int bx,by;while(cin>>m>>n){if(n==0 && m==0) break;fo(i,0,n-1){fo(j,0,m-1){cin>>room[i][j];if(room[i][j]=='@'){bx=i;by=j;}}}num=0;bfs(bx,by);cout<<num<<endl;}return 0;
}
这道题属于经典的模版题,没有什么特殊的难点。
1.4八数码问题与状态图搜索
八数码问题解析
康托展开
题目传送门
#include<bits/stdc++.h>
#define fo(i,a,b) for( int i=a;i<b;i++)
using namespace std;
const int LEN=362880;
struct node{int state[9];int dis;
};
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int visited[LEN]={0};
int state[9];
int goal[9];
long int factory[]={1,1,2,6,24,120,720,5040,40320,362880};//康托展开
bool Cantor(int str[],int n){long result = 0;fo(i,0,n){int counted=0;fo(j,i+1,n-1){if(str[i]>str[j]) ++counted;}result+=counted*factory[n-i-1];}if(!visited[result]){visited[result]=1;return 1;}else return 0;
}
int bfs(){node head;memcpy(head.state,state,sizeof(head.state));//复制起点状态head.dis=0;queue<node>q;Cantor(head.state,9);q.push(head);while(!q.empty()){head=q.front();q.pop();int z;for(z=0;z<9;z++){//找元素为0的位置 if(head.state[z]==0) {break;}}//转换为二维 int x=z%3;int y=z/3;fo(i,0,4){int newx=x+dir[i][0];int newy=y+dir[i][1];int nz=newx+3*newy;//转换为一维 if(newx>=0 && newx<3 && newy>=0 && newy<3){node newnode;memcpy(&newnode,&head,sizeof(struct node));//复制新状态swap(newnode.state[z],newnode.state[nz]);newnode.dis++;if(memcmp(newnode.state,goal,sizeof(goal))==0){return newnode.dis;} if(Cantor(newnode.state,9)){q.push(newnode);}} }} return -1;
}
int main(){fo(i,0,9) cin>>state[i];fo(i,0,9) cin>>goal[i];int num=bfs();if(num!=-1) cout<<num<<endl;else cout<<"Impossible"<<endl;return 0;
}
这道题与杭电oj上面的题有点不同
1.5 BFS与A*算法
这里用两篇文章来简单介绍一下
BFS
A*算法
简单来说,A*算法就是“BFS+贪心”。
上述八数码问题可以用这一算法来实现,因为我还没写出来,所以先空着,后序再来补充。
代码
1.6 双向广搜
双向广搜简介
题目传送门
1.7 DFS
题目传送门
#include<iostream>
#include<algorithm>
#include<string>
#define fo(i,a,b) for(int i=a;i<b;i++)
using namespace std;
int n,tot=0;
int col[12]={0};
bool check(int c,int r){fo(i,0,r){if(col[i]==c || (abs(col[i]-c)==abs(i-r))){return false;}}return true;
}
void dfs(int r){if(r==n) {tot++;return;}fo(c,0,n){if(check(c,r)){col[r]=c;dfs(r+1);}}
}
int main(){int ans[12]={0};fo(i,1,12){memset(col,0,sizeof(col));tot=0;n = i; dfs(0);ans[i-1]=tot; }while(cin>>n){if(n==0){return 0;}cout<<ans[n-1]<<endl; }return 0;
}
1.8 IDA*
题目传送门
#include<iostream>
#define fo(i,a,b) for( int i=a;i<b;i++)
using namespace std;
int val[1010];
int pos,n;
bool ida(int now,int depth){if(now>depth) return false;if(val[pos]<<(depth-now)<n) return false;if(val[pos]==n) return true;pos++;fo(i,0,pos){val[pos]=val[pos-1]+val[i];if(ida(now+1,depth)) return true;val[pos]=abs(val[pos-1]-val[i]);if(ida(now+1,depth)) return true;}pos--;return false;
}
int main(){while(cin>>n&&n){int depth;for(depth=0;;depth++){val[pos=0]=1;if(ida(0,depth)) break;}cout<<depth<<endl;}return 0;
}
文章持续更新中,如有不足之处欢迎留言