(POJ2488)A Knight's Journey
题目大意很明了,就是找到一个路径让马走完所有的点,不重复不遗漏;思路很容易找到,直接用DFS搜索标记并回溯,一个点一个点作为起点去试;找到后停止;
虽然感觉很简单,做的时候却没那么容易==|| 下面是AC代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 int dir[8][2]={-2,-1,-2,1,-1,-2,-1,2,1,-2,1,2,2,-1,2,1}; //记录方向 3 int g,a,b;//g用来记录是否找到解,找到后不再搜索 4 int vist[26][26],path[26][2]; 5 void find(int i,int j,int k)//i,j是要走的格子,k记录已经走过的步数 6 { 7 if(k==a*b)//走完了 8 { 9 for(int i=0;i<k;i++) 10 printf("%c%d",path[i][0]+'A',path[i][1]+1); 11 printf("\n"); 12 g=1; 13 } 14 else 15 for(int x=0;x<8;x++)//8个方向依次搜索 16 { 17 int n=i+dir[x][0]; 18 int m=j+dir[x][1]; 19 if(n>=0&&n<b&&m>=0&&m<a&&!vist[n][m]&&!g) 20 { 21 vist[n][m]=1;//标记已走 22 path[k][0]=n,path[k][1]=m; 23 find(n,m,k+1); 24 vist[n][m]=0;//清除标记 25 } 26 } 27 } 28 int main() 29 { 30 int n; 31 scanf("%d",&n); 32 for(int m=0;m<n;m++) 33 { 34 g=0; 35 scanf("%d %d",&a,&b); 36 for(int i=0;i<a;i++)//一个点一个点的尝试 37 for(int j=0;j<b;j++) 38 vist[i][j]=0; 39 vist[0][0]=1; 40 path[0][0]=0,path[0][1]=0; 41 printf("Scenario #%d:\n",m+1); 42 find(0,0,1); 43 if(!g) printf("impossible\n"); 44 printf("\n"); 45 } 46 return 0; 47 }
POJ3083 Children of the Candy Corn
题目大意:从入口S进到出口E,如果一直按照走左边的路(碰到墙后返回来继续),或一直选择向右走,各自需要多少步;和求最短路(简单BFS)
这道题虽说是一道题,却同时考察了DFS和BFS
当然,这道题的困难之处不在于DFS有多复杂,而在于如何一直向左走或向右走却不受位置的影响,解决办法是设置两个数组顺时针与逆时针,方法如下:
设左上右下为 0, 1, 2, 3 顺时针时,假设当前的前进方向为d, 那么从(d+2)%4,也就是相反方向开始循环,每次 (d+1)%4,遇到第一个能走的就前进。 逆时针时同理,不同的是每次(d-1+4)%4。
下面附上本人比较挫代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 #define mem(a) memset(a,0,sizeof(a)) 15 #define MAXN 1000000007 16 #define judge(x,y) x>=0&&x<m&&y>=0&&y<n&&map[x][y]!='#'&&!vis[x][y] 17 using namespace std; 18 int dir1[4][2]={{-1,0},{0,1},{1,0},{0,-1}};//顺时针 19 int dir2[4][2]={{0,-1},{1,0},{0,1},{-1,0}};//逆时针 20 char map[45][45]; 21 bool vis[45][45]; 22 int m,n; 23 struct node 24 { 25 int x,y; 26 int dist; 27 }; 28 int step,START_I; 29 int left_step=0,right_step=0; 30 31 int DFS(int x,int y,int I,int di[][2])//di[][0、1]区别向左还是向右 32 { 33 if(map[x][y]=='E')return 1; 34 int i,j; 35 for(j=0;j<4;j++) 36 { 37 i=(I+j+3)%4; 38 if(judge(x+di[i][0],y+di[i][1])){ 39 step=DFS(x+di[i][0],y+di[i][1],i,di)+1; 40 break; 41 } 42 } 43 return step; 44 } 45 46 int bfs(int x,int y)//BFS返回最小步数 47 { 48 mem(vis); 49 queue<node>q; 50 node u; 51 u.x=x;u.y=y;u.dist=0; 52 vis[u.x][u.y]=true; 53 q.push(u); 54 while(!q.empty()) 55 { 56 u=q.front(); 57 int d=u.dist,i; 58 if(map[u.x][u.y]=='E')return u.dist; 59 q.pop(); 60 for(i=0;i<4;i++) 61 { 62 node v; 63 v.x=u.x+dir1[i][0];v.y=u.y+dir1[i][1]; 64 if(judge(v.x,v.y)) 65 { 66 vis[v.x][v.y]=true; 67 v.dist=d+1; 68 q.push(v); 69 } 70 } 71 } 72 return 0; 73 } 74 int main() 75 { 76 int cas; 77 scanf("%d",&cas); 78 while(cas--) 79 { 80 mem(map);mem(vis); 81 scanf("%d%d",&n,&m); 82 int i,j,sx,sy; 83 for(i=0;i<m;i++) 84 { 85 scanf("%s",map[i]); 86 for(j=0;j<n;j++) 87 if(map[i][j]=='S')sx=i,sy=j; 88 } 89 90 //一直按向左走时,先找到出口的方向 91 for(i=0;i<4;i++) 92 if(judge(sx+dir1[i][0],sy+dir1[i][1])) 93 START_I=i; 94 step=0; 95 left_step=DFS(sx,sy,START_I,dir1);//DFS搜索 96 97 //向右 98 for(i=0;i<4;i++) 99 if(judge(sx+dir2[i][0],sy+dir2[i][1])) 100 START_I=i; 101 step=0;mem(vis); 102 right_step=DFS(sx,sy,START_I,dir2); 103 printf("%d %d %d\n",left_step,right_step,bfs(sx,sy)+1); 104 } 105 return 0; 106 }
POJ3009 Curling 2.0
题目大意:一个球只能走直线,切只能在碰到石头的时候才能停下来;而被碰到的石头将会消失;
走一次直线只算一步,求最少步数;
这道题呢,颠覆了我以前的思考,总觉得BFS和DFS只能一步一步向旁边走一步,却不知道还可以搜直线,而且一次搜到底部
题目给了一个条件就是当步数打不10时就认为是不能走到了,这复杂度就有了大大的减小;所以直接暴力每条路径搜完也不会超时;
代码:直接每条路搜索完全
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 1000000007 17 #define judge(x,y) x>=0&&x<h&&y>=0&&y<w&&map[x][y]!=1 18 int map[30][30]; 19 int w,h,sx,sy,ex,ey,step,steps,fin; 20 int d[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; 21 struct node 22 { 23 int x;int y; 24 int step; 25 }; 26 27 void DFS(int x,int y) 28 { 29 int i;if(step>10)return; 30 for(i=0;i<4;i++) 31 { 32 int nx,ny,ok; 33 ok=0; 34 nx=x+d[i][0],ny=y+d[i][1]; 35 while(judge(nx,ny)) 36 { 37 ok=1; 38 if(nx==ex&&ny==ey)if(step<steps)steps=step; 39 nx+=d[i][0],ny+=d[i][1]; 40 } 41 if(map[nx][ny]==1&&ok) 42 { 43 step++;map[nx][ny]=0; 44 DFS(nx-d[i][0],ny-d[i][1]); 45 step--;map[nx][ny]=1; 46 } 47 } 48 } 49 int main() 50 { 51 while(~scanf("%d%d",&w,&h)&&w&&h) 52 { 53 mem(map); 54 int i,j; 55 for(i=0;i<h;i++) 56 { 57 for(j=0;j<w;j++){ 58 scanf("%d",&map[i][j]); 59 if(map[i][j]==2)sx=i,sy=j; 60 if(map[i][j]==3)ex=i,ey=j; 61 } 62 } 63 steps=1000000; 64 step=1; 65 DFS(sx,sy); 66 printf("%d\n",steps>10?-1:steps); 67 } 68 return 0; 69 }
poj3278Catch That Cow
最水的BFS搜索了。。。。
在这里对BFS原理还做简单介绍,之后一律不讲
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #define mem(a) memset(a,0,sizeof(a)) 4 int vis[200005],q[200005],d[200005]; 5 int n,k; 6 void bfs(int x) 7 { 8 mem(vis);mem(q);mem(d); 9 vis[x]=1; 10 int front=0,rear=0;//front指向队列首,rear指向队列尾部 11 q[rear++]=x;//尾部加入一个 12 while(front<rear) 13 { 14 x=q[front++];//取出队列首的元素 15 if(x==k)return ;//如果找到了就返回 16 if(!vis[x-1]&&x>0){vis[x-1]=1;q[rear++]=x-1;d[x-1]=d[x]+1;}//如果x-1没有走过,则加在队列的尾部 17 if(!vis[x+1]&&x<100000){vis[x+1]=1;q[rear++]=x+1;d[x+1]=d[x]+1;}//与上面相似x+1 18 if(!vis[x*2]&&x<=50000){vis[x*2]=1;q[rear++]=2*x;d[x*2]=d[x]+1;}//一样x*2 19 } 20 } 21 int main() 22 { 23 while(~scanf("%d%d",&n,&k)) 24 { 25 bfs(n); 26 printf("%d\n",d[k]); 27 } 28 return 0; 29 }
poj2251Dungeon Master
这个不用多说,最简单的BFS求最短距离,只是改一下方向数组就可以,二维数组改为三维数组
下面是AC代码
对了,下面用的c++队列,其实很简单,就只有几种操作:
先介绍队列的定义 queue<类型名>变量名,如
queue<int>q,queue或queue<node>que;(struct node(结构体类型));
1、 q.front() 取出队首元素
2、 q.empty() 判断是否为空,时空返回1
3、 q.pop() 删除队首元素
4、 q.push(变量)加入变量
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 1000000007 17 #define judge(x,y,z) !vis[x][y][z]&&map[x][y][z]!='#'&&x>=0&&x<l&&y>=0&&y<m&&z>=0&&z<n 18 int d[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}}; 19 bool vis[35][35][35]; 20 char map[35][35][35]; 21 int l,m,n; 22 struct node 23 { 24 int x,y,z; 25 int step; 26 }; 27 int BFS(int x,int y,int z) 28 { 29 mem(vis); 30 queue<node>q; 31 node u; 32 u.x=x;u.y=y;u.z=z; 33 u.step=0; 34 q.push(u); 35 while(!q.empty()) 36 { 37 u=q.front(); 38 if(map[u.x][u.y][u.z]=='E')return u.step; 39 q.pop(); 40 int i; 41 for(i=0;i<6;i++) 42 { 43 node v; 44 v.x=u.x+d[i][0];v.y=u.y+d[i][1]; 45 v.z=u.z+d[i][2]; 46 if(judge(v.x,v.y,v.z)) 47 { 48 vis[v.x][v.y][v.z]=true; 49 v.step=u.step+1; 50 q.push(v); 51 } 52 } 53 } 54 return 0; 55 } 56 int main() 57 { 58 while(~scanf("%d%d%d%*c",&l,&m,&n)) 59 { 60 mem(map); 61 if(!m&&!n&&!l)break; 62 int i,j,k,sx,sy,sz; 63 for(i=0;i<l;i++) 64 for(j=0;j<m;j++){ 65 scanf("%s",map[i][j]); 66 for(k=0;k<n;k++) 67 { 68 if(map[i][j][k]=='S')sx=i,sy=j,sz=k; 69 } 70 } 71 int step=BFS(sx,sy,sz); 72 if(step)printf("Escaped in %d minute(s).\n",step); 73 else printf("Trapped!\n"); 74 } 75 return 0; 76 }
poj3414Pots
空杯子倒水问题,这题比较简单,只有两个杯子,最初的时候都是空的,要倒出指定量的水有三种操作:
1、FILL(i) 把第i个杯子装满(i=0,1)
2、DROP(i) 把第i个杯子倒空
3、POUR(i,j) 把i的水倒入到j中,直到j满或i倒完
我的想法:把a->b,b->c,。。。。共6种倒水方法一个一个列出来,而每种都是一样的讨论方法,
虽然很好做,但对于我这样的入门级水手来说还是写不出太好看的代码,所以。。。。
看看吧,看不懂再去看看网上别人的==||
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 1000000007 17 char op[6][20]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"}; 18 int vis[110][110],fa[110][110],opp[110][110];//0~5->fill a,fill b,drop a,drop b,pour a-b,pour b-a 19 int sa,sb; 20 struct pot 21 { 22 int a,b; 23 int step; 24 }; 25 void print(int a,int b) 26 { 27 if(opp[a][b]==-1)return; 28 else { 29 print(fa[a][b]/1000,fa[a][b]%1000); 30 printf("%s\n",op[opp[a][b]]); 31 } 32 } 33 int BFS(int C) 34 { 35 mem(vis);mem(fa);mem(opp); 36 pot u; 37 u.a=0;u.b=0;u.step=0; 38 opp[0][0]=-1; 39 fa[0][0]=0; 40 vis[0][0]=1; 41 queue<pot>q; 42 q.push(u); 43 while(!q.empty()) 44 { 45 u=q.front(); 46 q.pop(); 47 if(u.a==C||u.b==C){printf("%d\n",u.step);print(u.a,u.b);return 1;} 48 pot v=u; 49 if(u.a!=sa)//是不是没有装满 50 {v.a=sa; 51 if(!vis[v.a][v.b]){//是不是没有搜过 52 v.step++; 53 q.push(v); 54 opp[v.a][v.b]=0; 55 vis[v.a][v.b]=1; 56 fa[v.a][v.b]=u.a*1000+u.b; 57 } 58 }v=u; 59 if(u.b!=sb){v.b=sb; 60 if(!vis[v.a][v.b]){ 61 v.step=u.step+1; 62 q.push(v); 63 opp[v.a][v.b]=1; 64 vis[v.a][v.b]=1; 65 fa[v.a][v.b]=u.a*1000+u.b; 66 } 67 }v=u; 68 if(u.a){v.a=0; 69 if(!vis[v.a][v.b]){ 70 v.step=u.step+1; 71 q.push(v); 72 opp[v.a][v.b]=2; 73 vis[v.a][v.b]=1; 74 fa[v.a][v.b]=u.a*1000+u.b; 75 } 76 }v=u; 77 if(u.b){v.b=0; 78 if(!vis[v.a][v.b]){ 79 v.step=u.step+1; 80 q.push(v); 81 opp[v.a][v.b]=3; 82 vis[v.a][v.b]=1; 83 fa[v.a][v.b]=u.a*1000+u.b; 84 } 85 }v=u; 86 if(u.a){ 87 if(v.a>=sb-u.b&&u.b!=sb){v.a-=(sb-u.b);v.b=sb;} 88 else if(v.a<sb-u.b){v.a=0;v.b+=u.a;} 89 if(!vis[v.a][v.b]){ 90 v.step=u.step+1; 91 q.push(v); 92 opp[v.a][v.b]=4; 93 vis[v.a][v.b]=1; 94 fa[v.a][v.b]=u.a*1000+u.b; 95 } 96 }v=u; 97 if(u.b) 98 { 99 if(v.b>=sa-u.a&&u.a!=sa){v.b-=(sa-u.a);v.a=sa;} 100 else if(v.b<sa-u.a){v.b=0;v.a+=u.b;} 101 if(!vis[v.a][v.b]){ 102 v.step=u.step+1; 103 q.push(v); 104 opp[v.a][v.b]=5; 105 vis[v.a][v.b]=1; 106 fa[v.a][v.b]=u.a*1000+u.b; 107 } 108 } 109 } 110 return 0; 111 } 112 int main() 113 { 114 int c; 115 while(~scanf("%d%d%d",&sa,&sb,&c)&&c) 116 { 117 int ok=BFS(c); 118 if(!ok)printf("impossible\n"); 119 } 120 return 0; 121 }
POJ1321棋盘问题
题目大意很明确,就是求k个棋子放在一盘棋上,其中有些可以放,有些不可以;问有多少种方法使得每行每列只有一个棋子。
由于题目给的数据范围比较小(n<=8),所以可以用深搜(数据较大的话可以去百度参考状态压缩),还是采用标记搜索去除标记的方法,只是要注意边界条件以及回溯的条件;思路已经在代码里了:看看吧。。。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 100000007 17 int num[9],number[9][9],n,k;//num记录每一行的可行数,number记录可行所在的列 18 char map[9]; 19 bool vis[9]; 20 int method,put; 21 void DFS(int cur) 22 { 23 if(k==put){method++;return;}//如果找到了(当然也包括第k个放在最后一行的情况) 24 if(cur==n||k-put>n-cur)return ;//如果超出边界或剩下的行数比需要放下的少 25 int i; 26 if(!num[cur]){DFS(cur+1);return;}//如果一行为空 27 int flag=1; 28 for(i=0;i<num[cur];i++) 29 { 30 if(!vis[number[cur][i]]){ 31 put++;vis[number[cur][i]]=true;//放一个 32 DFS(cur+1); 33 put--;vis[number[cur][i]]=false;//不放 34 } 35 } 36 DFS(cur+1); //这一行不放,直接搜索下一行 ,但是只能搜一次,不然会重复 37 } 38 int main() 39 { 40 while(~scanf("%d%d%*c",&n,&k)) 41 { 42 if(n==-1&&k==-1)break; 43 int i,j;mem(number);mem(num); 44 for(i=0;i<n;i++){ 45 scanf("%s",map); 46 for(j=0;j<n;j++) 47 if(map[j]=='#')number[i][num[i]++]=j;//记录每一行的个数与所在的列数 48 } 49 mem(vis);put=0;method=0; 50 DFS(0); 51 printf("%d\n",method); 52 } 53 }
其中我加了一句(k-put>n-cur) 24行,时间花了16Ms,如果删去,也可以过,时间却要花上63Ms,所以优化优化再优化。。。。
POJ1426Find The Multiple
题目的意思就是给你一个数n,让你找到一个它的倍数只由1和0组成。(任何一个都可以,Special Judge)
最开始自己怕数据太大,就用数组存放1和0,再一一判断,结果TLE,实在是没有办法了,在网上搜寻别人的代码,看了看discuss
发现一个奇葩的代码:我也不知道怎么评价这代码了,只能说我Orz。。。。。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 #include <stdlib.h> 3 #include <iostream> 4 int s=0; 5 6 using namespace std; 7 void bag(__int64 p,int n,int k) 8 { 9 if(s==1||k==20) 10 return; 11 if(p%n==0) 12 { 13 printf("%I64u\n",p); 14 s=1; 15 } 16 else 17 { 18 bag(10*p,n,k+1); 19 bag(10*p+1,n,k+1); 20 } 21 } 22 23 int main() 24 { 25 int n; 26 while(cin>>n,n) 27 { 28 s=0; 29 bag(1,n,1); 30 } 31 return 0; 32 }
POJ3126Prime Path
题目大意就是给两个四位的素数a,b,每次替换a的一个数位,让a变到b,但是每次替换中所生成的新四位数也必须是素数。求最少要多少步。
简单的BFS直接替换每个数位即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 1000000007 17 int vis[10000]; 18 int m; 19 struct number 20 { 21 int num,step; 22 }; 23 int isprime(int n) 24 { 25 int i; 26 for(i=2;i*i<=n;i++)if(n%i==0)return 0; 27 return 1; 28 } 29 int BFS(int target) 30 { 31 mem(vis); 32 number u; 33 u.num=m;u.step=0; 34 queue<number>q; 35 q.push(u); 36 while(!q.empty())//队列不为空时 37 { 38 u=q.front();//取队列首元素 39 q.pop();//删除队列首元素 40 if(u.num==target)return u.step; 41 int i,j; 42 for(i=3;i>=0;i--)//从最高位开始 43 { 44 double p=(double)pow((double)10,(int)i); 45 int x=(u.num/(int)p)%10; 46 for(j=0;j<10;j++) 47 { 48 if(i==3&&j==0)continue;//最高位不能为0 49 int y=u.num+(j-x)*p;//判断下一个数 50 if(!vis[y]&&isprime(y))//如果没有搜索过且是素数 51 { 52 vis[y]=1; 53 number v;v.num=y;v.step=u.step+1; 54 q.push(v); 55 } 56 } 57 } 58 } 59 return -1; 60 } 61 int main() 62 { 63 int n; 64 scanf("%d",&n); 65 while(n--) 66 { 67 int target; 68 scanf("%d%d",&m,&target); 69 int ok=BFS(target); 70 if(ok!=-1)printf("%d\n",ok); 71 else printf("Impossible\n"); 72 } 73 return 0; 74 }
POJ2676Sudoku
数独,提议就不用解释了吧。。。。
我用row[k][i]表示第k行是否已经有数i
col[k][i]表示第k列是否已经有数i
而sq[k][i]表示第k个九宫格是否有数i(这里k=(x/3)*3+(y/3),可以想想为什么)
从0,0 依次搜到8,8 DFS依次往下,看代码:(已有注释)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 100000007 17 bool col[9][9],row[9][9],sq[9][9],vis[9][9]; 18 int map[9][9]; 19 bool Isfind; 20 void print() 21 { 22 int i,j; 23 for(i=0;i<9;i++){ 24 for(j=0;j<9;j++) 25 printf("%d",map[i][j]+1); 26 printf("\n"); 27 } 28 } 29 void DFS(int x,int y) 30 { 31 int u=x*9+y+1,i; 32 if(x==9){//全部都满足了 33 Isfind=true;//标记已经找到 34 print();//打印 35 } 36 if(Isfind)return ;//找到了就不用再搜索 37 if(map[x][y]!=-1){ 38 DFS(u/9,u%9);//如果本来就已经有数,直接搜索下一个 39 return; 40 } 41 for(i=0;i<9&&!Isfind;i++) 42 { 43 int k=(x/3)*3+y/3; 44 if(!row[x][i]&&!col[y][i]&&!sq[k][i]) 45 { 46 row[x][i]=col[y][i]=sq[k][i]=true;map[x][y]=i;//标记并把map赋值 47 DFS(u/9,u%9); //搜下一个 48 row[x][i]=col[y][i]=sq[k][i]=false;map[x][y]=-1;//清除标记 49 } 50 } 51 } 52 int main() 53 { 54 int i,j,cas;char q; 55 scanf("%d",&cas); 56 while(cas--){ 57 mem(vis);mem(map); 58 mem(row);mem(col);mem(sq); 59 for(i=0;i<9;i++) 60 for(j=0;j<9;j++){ 61 cin>>q; 62 map[i][j]=q-'1'; 63 if(q-'0') 64 row[i][q-'1']=col[j][q-'1']=sq[(i/3)*3+(j/3)][q-'1']=true; 65 } 66 Isfind=false; 67 DFS(0,0); 68 } 69 }
这行代码花了563毫秒,然后如果从8,8搜到0,0结果就只有16毫秒,代码在下面:(就稍稍改了一下)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<queue> 5 #include<string> 6 #include<stack> 7 #include<cmath> 8 #include<cctype> 9 #include<iostream> 10 #include<set> 11 #include<algorithm> 12 #include<ctime> 13 #include<vector> 14 using namespace std; 15 #define mem(a) memset(a,0,sizeof(a)) 16 #define MAXN 100000007 17 bool col[9][9],row[9][9],sq[9][9],vis[9][9]; 18 int map[9][9]; 19 bool Isfind; 20 void print() 21 { 22 int i,j; 23 for(i=0;i<9;i++){ 24 for(j=0;j<9;j++) 25 printf("%d",map[i][j]+1); 26 printf("\n"); 27 } 28 } 29 void DFS(int x,int y) 30 { 31 int u=x*9+y-1,i; 32 if(x==-1){ 33 Isfind=true; 34 print(); 35 } 36 if(Isfind)return ; 37 if(map[x][y]!=-1){ 38 DFS(u/9,u%9); 39 return; 40 } 41 for(i=0;i<9&&!Isfind;i++) 42 { 43 int k=(x/3)*3+y/3; 44 if(!row[x][i]&&!col[y][i]&&!sq[k][i]) 45 { 46 row[x][i]=col[y][i]=sq[k][i]=true;map[x][y]=i; 47 DFS(u/9,u%9); 48 row[x][i]=col[y][i]=sq[k][i]=false;map[x][y]=-1; 49 } 50 } 51 } 52 int main() 53 { 54 int i,j,cas;char q; 55 scanf("%d",&cas); 56 while(cas--){ 57 mem(vis);mem(map); 58 mem(row);mem(col);mem(sq); 59 for(i=0;i<9;i++) 60 for(j=0;j<9;j++){ 61 cin>>q; 62 map[i][j]=q-'1'; 63 if(q-'0'){ 64 row[i][q-'1']=true; 65 col[j][q-'1']=true; 66 sq[(i/3)*3+(j/3)][q-'1']=true; 67 } 68 } 69 Isfind=false; 70 DFS(8,8); 71 } 72 }