今天是训练的第一天,主要复习了一下搜索的使用,包括深搜和广搜,除了复习了课件以及相关例题课件之外,完成了数道训练题目。
总结今天的训练,认为做搜索题需要掌握其独有的方法,需要先弄清是深搜还是广搜。然后想搜什么,怎么搜,需要在哪里进行剪枝,需要在哪里进行优化。
然后分别套用模板代码即可。
分别是:
BFS:
queue<要查的对象>qq;
while(!qq.empty()){
下一层对象的原点=qq.front();
判断是否到达终点:yes-结束(return);
no-继续寻找。
if(判断条件成立)qq.push(新的点);//将新得到的对象压入队列中。
}
在广搜中,要搜查的对象就是一开始提到的想要搜什么,怎么搜主要是指判断过程条件,达到什么条件压进队列等等。
DFS:
这种题型的代码类似于递归的结构:
int search(已经搜索的次数){
判断是否结束,yes-return
no-继续执行
if(判断条件成立)//这里指找到了下一个点,search(次数+1)
复原状态;(这里尤为重要)
}
这两种题在思路方面不存在很大的障碍问题,重点是读懂题意,找寻判断过程的条件,而难点就是尽可能的降低复杂度,比如今天做的一个题目:
这个题目的主要意思就是要我们用程序玩一个数独游戏,每行每列不能重复,规定的3*3的块中也不能存在重复,这里,判断条件就是三个数组,比较好想
但是真正的难点在于怎么减少时间的复杂度,一开始我选择在执行的过程中查找空点,再用空点进行条件判断,但这样大大拖慢了时间的复杂度,于是选择了
换用一开始记住点的位置,对点进行查找的方法,解决了时间复杂的问题,最终处理了较难的样例。
代码如下:
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
bool r[9][10],c[9][10],fun[10][10];
char m[9][9];
int total;
struct point{
int x;
int y;
};
struct point p[100];
void print(){
for (int i=0;i<9;i++){
for (int j=0;j<9;j++){
cout<<m[i][j];
}
cout<<endl;
}
}
int judge(int xx,int yy){
return (xx/3)*3+yy/3;
}
int search(int n){
int i,j,k,l;
if (n>total)return 1;
//cout<<total<<endl;
for (i=1;i<=9;i++){
//cout<<judge(p[n].x+1,p[n].y+1)<<endl;
if (!r[p[n].x][i]&&!c[p[n].y][i]&&!fun[judge(p[n].x,p[n].y)][i]){
m[p[n].x][p[n].y]=i+'0';
r[p[n].x][i]=1;
c[p[n].y][i]=1;
fun[judge(p[n].x,p[n].y)][i]=1;
if (search(n+1))
return 1;
r[p[n].x][i]=0;
c[p[n].y][i]=0;
fun[judge(p[n].x,p[n].y)][i]=0;
}
}
return 0;
}
int main(){
int i,j,k,l,t;
cin>>t;
for (k=1;k<=t;k++){
memset (r,0,sizeof(r));
memset (c,0,sizeof(c));
memset (fun,0,sizeof(fun));
for (i=0;i<9;i++){
cin>>m[i];
}
for (i=0,total=0;i<9;i++){
for (j=0;j<9;j++){
if (m[i][j]=='0'){
total+=1;
p[total].x=i;
p[total].y=j;
}
else {
r[i][m[i][j]-'0']=1;
c[j][m[i][j]-'0']=1;
int kk=judge(i,j);
fun[kk][m[i][j]-'0']=1;
}
}
}
search(1);
print();
}
}
此外还完成了4道题,其中广搜3道,深搜1道,巩固了知识点,但简单题居多,思维的发散性方面有待加强。思路有时候局限性强,导致不能想到最佳方案,便急于摸键盘, 这终究是对付水题的方案,而不是处理难题的上上策,在这方面还需加强。对于图论的相关内容出现大批遗忘,在当时就缺少训练,后来又怠于复习,更需在日后的训练中加强对这一方面的复习。