更新下c++中搜索算法,用在一般算法竞赛中是DFS和BFS。当然,一些启发式搜索,例如遗传算法,模拟退火等。一般算法竞赛中不会涉及。
DFS:
//算法框架 void dfs(int n){ if(搜索结束){ 记录结果。 return; } for(遍历所有解){ if(合法的解){ 占位。 } dfs(n+1); 取消占位。 } }
算法框架如上,对于一些简单的问题,相当于填空了。
经典例题N皇后
上代码87分,超时代码
#include<iostream> #include<cstdio> using namespace std; const int maxn=15; int N,cnt,a[maxn][maxn]; void dfs(int n){ if(n==N+1){//递归结束 if(cnt<3){ //满足条件输出前三组解 for(int i=1;i<=N;i++){ for(int j=1;j<=N;j++){ if(a[i][j]==1){ cout<<j<<" "; break; } } } cout<<endl; } cnt++; return; } for(int i=1;i<=N;i++){ //遍历每一行所有可能结果 int flag=1; for(int j=0;(n-j)>=1;j++){ //向上寻找 if(a[n-j][i]==1){ flag=0; break; } } if(!flag) continue; //上方已经有皇后 for(int j=1;(n-j)>=1&&(i+j)<=N;j++){//右上方寻找 if(a[n-j][i+j]==1){ flag=0; break; } } if(!flag) continue; for(int j=1;(n-j)>=1&&(i-j)>=1;j++){//左上方寻找 if(a[n-j][i-j]==1){ flag=0; break; } } if(!flag) continue; if(flag){ //可以占位 a[n][i]=1; //占位 dfs(n+1);//寻找下一层 a[n][i]=0; //取消占位 } } return ; } int main(){ cin>>N; dfs(1); cout<<cnt; return 0; }
上面的代码是正确的,只不过在n=13的时候,运行时间是1.2s超时了,是TLE没有AC。思路很简单,用二维数组,模拟棋盘。因为每行,列以及两条对角线不能放皇后。因此,用递归的层数表示行也就是变量n,所有的解就是每一列也就是变量i,每次放皇后时,检查每一列,以及对角线,满足要求就放下,否则继续搜索。
弄清变量n,i的含义,理清思路即可。
好久不练了,不难的一道题写了两个版本共计2个半小时。。。
接着,上AC代码,二维变一维,智商被碾压。
#include<cstdio> using namespace std; const int maxn=100; int a[maxn],n,ans=0; int b1[maxn],b2[maxn],b3[maxn]; void dfs(int x){ if(x>n){ ans++; if(ans<=3){ for(int i=1;i<=n;i++){ printf("%d ",a[i]); } puts(" "); } return; } for(int i=1;i<=n;i++){ if(b1[i]==0&&b2[i]==0&&b3[i]==0){ a[x]=i; b1[i]=1;b2[x+i]=1;b3[x-i+15]=1; dfs(x+1); b1[i]=0;b2[x+i]=0;b3[x-i+15]=0; } } } int main(){ scanf("%d",&n); dfs(1); printf("%d",ans); return 0; }
代码用三个数组表示每一列,以及两条对角线。对于列来说,它的y是定值,对于两条对角线,x+y或者x-y是定值。由于x-y可能会小于0,用偏移量16保证大于0,即可。