网站:CSUST 8月1日
先总结下,不得不说死的很惨,又是第三就不说了,一共7道题,AC了5道,但是有一个组三个人是做的个人赛,有两人AK了.......Orz,然后深搜还是大问题,宽搜倒是不急了。
而且,其中还有一题是水过去的。唉,不说了,好好看。╮(╯▽╰)╭
A 骑士历遍问题:给出m,n,指大小为m*n的棋盘,问骑士是否能遍历整个棋盘,要求把路径打出来,(要按字典序)A Knight's Journey POJ 2488
网上找到了个很好地代码,解释很清晰:http://www.slyar.com/blog/poj-2488-c.html (以下解释来自这里)
Slyar:说一下题目大意。给出一个国际棋盘的大小,判断马能否不重复的走过所有格,并记录下其中按字典序排列的第一种路径。
"马的遍历"是一道经典回溯题,当然还是DFS...这题有3个要密切注意的地方:
1、题目要求以"lexicographically"方式输出,也就是字典序...一开始没看懂这个词结果WA了N次...要以字典序输出路径,那么方向数组就要以特殊的顺序排列了...这样只要每次从dfs(1,1)开始搜索,第一个成功遍历的路径一定是以字典序排列...
2、国际象棋的棋盘,横行为字母,表示横行坐标的是y;纵行为数字,表示纵行的坐标是x...一开始又搞反了...
代码:16MS
1 #include2 #include<string.h> 3 #include 4 using namespace std; 5 int map[30][30],x[30],y[30]; 6 int d[8][2]={{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},{1, -2}, {1, 2}, {2, -1}, {2, 1}}; //字典序 7 int m,n,sign,step; 8 void dfs(int i,int j) 9 { 10 int a,b,k; 11 if(sign) //以历遍,跳出 12 return ; 13 step++; 14 x[step]=i; //当前位置 15 y[step]=j; 16 if(step==m*n) //步数=格子数 17 { 18 sign=1; 19 return ; 20 } 21 map[i][j]=1; //标记 22 for(k=0;k<8;k++) 23 { 24 b=j+d[k][0]; //注意 25 a=i+d[k][1]; 26 if(map[a][b]==0 && a>0 && b>0 && a<=m && b<=n) 27 { 28 dfs(a,b); 29 step--; //不符合要求是回溯步数 30 31 } 32 } 33 map[i][j]=0; //返回 34 } 35 int main() 36 { 37 int T,i,t=0; 38 scanf("%d",&T); 39 while(T--) 40 { 41 scanf("%d%d",&m,&n); 42 t++; 43 memset(map,0,sizeof(map)); 44 step=0; 45 sign=0; 46 dfs(1,1); 47 printf("Scenario #%d:\n", t); 48 if(sign) 49 { 50 for(i=1;i<=m*n;i++) 51 printf("%c%d",y[i]+64,x[i]); //注意这里,先是y,再是x 52 printf("\n\n"); //要空一行 53 } 54 else printf("impossible\n\n"); //要空一行 55 } 56 return 0; 57 }
B 大意是:找出最大的湖泊的格子数,只能上下左右,对角不算相连 Avoid The Lakes POJ 3620
代码: 16ms BFS
1 #include2 #include 3 #include<string.h> 4 using namespace std; 5 int d[4][2]={{1,0},{0,1},{0,-1},{-1,0}}; 6 int map[105][105]; 7 int m,n; 8 class A 9 { 10 public: 11 int a; 12 int b; 13 }; 14 A q[10025]; 15 void bfs() 16 { 17 A r,t; 18 int i,j,ans,k,maxn=0; 19 for(j=1;j<=m;j++) //扫描 20 for(k=1;k<=n;k++) 21 { 22 if(map[j][k]==1) 23 { 24 ans=1; 25 int g=0; 26 int h=0; 27 map[j][k]=0; //标记 28 q[g].a=j; //开始的位置 29 q[g].b=k; 30 g++; 31 while(h!=g) 32 { 33 r=q[h++]; 34 for(i=0;i<4;i++) 35 { 36 t.a=r.a+d[i][0]; 37 t.b=r.b+d[i][1]; 38 if(t.a>0 && t.a<=m && t.b>0 && t.b<=n && map[t.a][t.b]==1) //满足条件 39 { 40 q[g++]=t; 41 map[t.a][t.b]=0; //标记 42 ans++; 43 } 44 } 45 } 46 if(maxn //找出最大值 47 maxn=ans; 48 } 49 } 50 cout< endl; 51 } 52 int main() 53 { 54 int i,j,k,x; 55 memset(map,0,sizeof(map)); 56 while(~scanf("%d%d%d",&m,&n,&x)) 57 { 58 for(i=0;i ) 59 { 60 scanf("%d%d",&j,&k); 61 map[j][k]=1; 62 } 63 bfs(); 64 } 65 return 0; 66 }
另一种方法:DFS 16MS
1 #include2 #include<string.h> 3 #include 4 #include 5 using namespace std; 6 int b[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 7 int a[105][105]; 8 int n,m,s; 9 void dfs(int i,int j) 10 { 11 int k,x,y; 12 s++; 13 a[i][j]=0; //标记 14 for(k=0;k<4;k++) 15 { 16 x=i+b[k][0]; 17 y=j+b[k][1] ; 18 if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]==1) //满足条件 19 dfs(x,y); 20 } 21 } 22 int main() 23 { 24 int t,a1,b1,i,j,MAX; 25 while(~scanf("%d%d%d",&n,&m,&t)) 26 { 27 s=0; 28 memset(a,0,sizeof(a)); 29 for(i=0;i ) 30 { 31 scanf("%d %d",&a1,&b1); 32 a[a1][b1]=1; 33 } 34 MAX=0; 35 for(i=1;i<=n;i++) 36 for(j=1;j<=m;j++) // 遍历能够开始的点 37 if(a[i][j]==1) 38 { 39 dfs(i,j); 40 if(s>MAX) //找到最大值 41 MAX=s; 42 s=0; 43 } 44 printf("%d\n",MAX); 45 } 46 return 0; 47 }
C 大意是:一个Z层x*y的楼房,要从起点到中点,问最少要走多少步? 6个方向 Dungeon Master POJ 2251
代码: 0MS
1 #include2 #include 3 #include 4 using namespace std; 5 int number,Z,X,Y,x1,y1,z1,x2,y2,z2; 6 const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}}; //上下左右前后6个方向 7 char a[30][30][30]; 8 class K 9 { 10 public: 11 int x,y,z,step; 12 }k[1000000]; 13 void bfs(int z,int x,int y) 14 { 15 int f=0,r=1,i,hx,hy,hz; 16 k[0].x=x; //开始位置 17 k[0].y=y; 18 k[0].z=z; 19 k[0].step=0; 20 a[z][x][y]='#'; //标记 21 while(f<r) 22 { 23 for(i=0;i<6;i++) 24 { 25 hx=k[f].x+add[i][0]; 26 hy=k[f].y+add[i][1]; 27 hz=k[f].z+add[i][2]; 28 if(hx>=0 && hx =0 && hy =0 && hz '.' ||a[hz][hx][hy]=='E') ) 29 { 30 if(a[hz][hx][hy]=='E') 31 {number=k[f].step+1; return;} 32 k[r].x=hx; 33 k[r].y=hy; 34 k[r].z=hz; 35 k[r++].step=k[f].step+1; 36 a[hz][hx][hy]='#'; 37 } 38 } 39 f++; 40 } 41 return; 42 } 43 int main() 44 { 45 while(scanf("%d%d%d",&Z,&X,&Y)&&Z&&Y&&X) 46 { 47 int i,j,k; 48 memset(a,0,sizeof(a)); 49 for(i=0;i //输入地图 50 for(j=0;j ) 51 scanf("%s",a[i][j]); 52 for(i=0;i ) 53 for(j=0;j ) 54 for(k=0;k ) 55 if(a[i][j][k]=='S') //起点 56 { 57 x1=j; 58 y1=k; 59 z1=i; 60 } 61 number=0; 62 bfs(z1,x1,y1); 63 if(number==0) 64 printf("Trapped!\n"); 65 else 66 printf("Escaped in %d minute(s).\n",number); 67 } 68 return 0; 69 }
D 大意是:给出一个数m,要用n个数来凑,这n个数分别是a1,a2,a3a.....an.输出加法式 Sum It Up HDU 1258
代码: 15MS
1 #include
2 int t,n,flag,a[20],b[20];
3 void dfs(int j,int k,int g)
4 { 5 int i; 6 if(j>t) 7 return ; 8 if(j==t) //凑成了t 9 { 10 flag=0; //至少有一种凑的方法 11 for(i=0;i1;i++) 12 printf("%d+",b[i]); 13 printf("%d\n",b[g-1]); //打出等式 14 return ; 15 } 16 int last=-1; 17 for(i=k;i //和每个排在自己之后的数加一次 18 { 19 if(j+a[i]>t) //超过就跳过 20 continue; 21 if(a[i]!=last) //不等于最后加的一个数,否则等式一样 22 { 23 last=b[g]=a[i]; //更新最后加的数 24 dfs(j+a[i],i+1,g+1); 25 } 26 } 27 } 28 int main() 29 { 30 int i; 31 while(~scanf("%d%d",&t,&n)&&n&&t) 32 { 33 flag=1; 34 for(i=0;i ) 35 scanf("%d",&a[i]); 36 printf("Sums of %d:\n",t); 37 dfs(0, 0, 0); 38 if(flag) 39 printf("NONE\n"); 40 } 41 }
另一份代码: 0ms
1 #include2 #include<string.h> 3 const int N=20; 4 int a[N],n,t,flag; 5 bool vis[N]; 6 void print() 7 { 8 flag=1; 9 bool bol=0; 10 int i; 11 for (i=1;i<=n;i++) 12 if (vis[i]) //判断要不要加 13 { 14 if (bol) printf("+%d",a[i]); 15 else {bol=1; printf("%d",a[i]);} //加的第一个数 16 } 17 printf("\n"); 18 } 19 void dfs(int s,int p) 20 { 21 if (s==t) {print(); return;} 22 int i; 23 for (i=p+1;i<=n;i++) //s和最后一个加数之后所有的数加一次 24 { 25 vis[i]=1; //标记,代表加了这个数 26 if (s+a[i]<=t) 27 dfs(s+a[i],i); 28 vis[i]=0; //不满足则退回到上一步 29 while (i<=n && a[i]==a[i+1]) //一样的数不用再加,否则会重复 30 i++; 31 } 32 } 33 int main() 34 { 35 int i; 36 while (scanf("%d%d",&t,&n),n||t) 37 { 38 flag=0; 39 for (i=1;i<=n;i++) 40 scanf("%d",&a[i]); 41 printf("Sums of %d:\n",t); 42 dfs(0,0); 43 if (!flag) printf("NONE\n"); 44 } 45 return 0; 46 }
E大意是:在N*N的棋盘上放N个皇后,每两个皇后不能在同一行,同一列,也不能再同一斜线上(45°斜线),问有多少种方法?
这一道题我们是水过去的,因为规定了N<=10,所以只有10种情况,一一列举出来。╮(╯▽╰)╭
以下解释&&代码来自http://blog.sina.com.cn/s/blog_696187fd0100p5ri.html# (我修改了一些地方)
方法一: 递归回溯 //会超时......
1 #include2 #include 3 #define N 15 4 int n; //皇后个数 5 int sum = 0; //可行解个数 6 int x[N]; //皇后放置的列数 7 int place(int k) 8 { 9 int i; 10 for(i=1;i ) 11 if(fabs(k-i)==fabs(x[k]-x[i]) || x[k] == x[i]) //fabs(k-i)==fabs(x[k]-x[i])是在同一斜线上,x[k] == x[i]在同一列 12 return 0; 13 return 1; 14 } 15 int queen(int t) 16 { 17 if(t>n) //当放置的皇后超过n时,可行解个数加1 18 sum++; 19 else 20 for(int i=1;i<=n;i++) 21 { 22 x[t] = i; //标明第t个皇后放在第i列 23 if(place(t)) //如果可以放在某一位置,则继续放下一皇后 24 queen(t+1); 25 } 26 return sum; 27 } 28 int main() 29 { 30 while(~scanf("%d",&n)&&n) 31 { 32 sum=0; 33 int t = queen(1); 34 printf("%d\n",t); 35 } 36 return 0; 37 }
方法二:迭代回溯 可以理解但是....他是肿么想出来的.....其实和上面那个方法差不多,但是不是用递归实现的
1 #include2 #include 3 #define N 15 4 int n; 5 int sum = 0; 6 int x[N]; 7 int place(int k) //判断能不能放这~~~ 8 { 9 int i; 10 for(i=1;i ) 11 if(fabs(k-i)==fabs(x[k]-x[i]) || x[k] == x[i]) //fabs(k-i)==fabs(x[k]-x[i])是在同一斜线上,x[k] == x[i]是在同一列上 12 return 0; 13 return 1; 14 } 15 int queen() 16 { 17 x[1] = 0; 18 int t=1; 19 while(t>0) 20 { 21 x[t]+=1; 22 while(x[t]<=n && !place(t)) //一列列试,不行则放下一列 23 x[t]++; 24 if(x[t]<=n ) 25 if(t==n) 26 sum++; 27 else 28 x[++t] = 0; 29 else 30 t--; //满了则退回一步 31 } 32 return sum; 33 } 34 int main() 35 { 36 int t; 37 while(~scanf("%d",&n),n) 38 { 39 sum=0; 40 t = queen(); 41 printf("%d\n",t); 42 } 43 return 0; 44 }
这样用记忆法才不会超时 15MS
1 #include2 #include 3 #include 4 using namespace std; 5 int n,x[15],sum,a[15]; 6 int place(int i) 7 { 8 for(int j=1;j) 9 if(fabs(i-j)==fabs(x[i]-x[j]) || x[i]==x[j]) 10 return 0; 11 return 1; 12 } 13 int qeen(int i) 14 { 15 if(i>n) 16 sum++; 17 else 18 for(int j=1;j<=n;j++) 19 { 20 x[i]=j; 21 if(place(i)) 22 qeen(i+1); 23 } 24 return sum; 25 } 26 int main() 27 { 28 for(n=1;n<=10;n++) 29 { 30 sum=0; 31 a[n]=qeen(1); 32 } 33 while(~scanf("%d",&n)&&n) 34 printf("%d\n",a[n]); 35 return 0; 36 }
E 大意是:找出棋盘上最多能放的棋子数,不能同一行同一列(隔开了就可以),允许在同一斜线上。
1:棋盘。2:正确的方法(也是最多的),3正确,4&5错误.
和N皇后有点像,指不过斜线也可以放,而且有墙,隔开也可以放。
代码: 来自:http://blog.csdn.net/hcbbt/article/details/9420387 15MS,头文件加上#include
1 #include2 const int maxn = 5; 3 char map[maxn][maxn]; 4 int ans, n; 5 bool isok(int x, int y) 6 { 7 for (int i = x + 1; i <= n && map[i][y] != 'X'; i++) //遇到'X'就不再搜了 8 if(map[i][y] == '0') 9 return false; 10 for (int i = x - 1; i >= 1 && map[i][y] != 'X'; i--) 11 if(map[i][y] == '0') 12 return false; 13 for (int i = y + 1; i <= n && map[x][i] != 'X'; i++) 14 if (map[x][i] == '0') 15 return false; 16 for (int i = y - 1; i >= 1 && map[x][i] != 'X'; i--) 17 if (map[x][i] == '0') 18 return false; 19 return true; 20 } 21 void dfs(int x, int y, int p) 22 { 23 for (int i = 1; i <= n; i++) 24 for (int j = 1; j <= n; j++) 25 if (map[i][j] == '.' && isok(i, j)) 26 { 27 map[i][j] = '0'; //代表已经放了一颗棋子 28 dfs(i, j, p + 1); 29 map[i][j] = '.'; 30 } 31 if (ans < p) 32 ans = p; 33 } 34 int main() 35 { 36 while (scanf("%d", &n) && n) 37 { 38 gets(map[0]); //可改成用scanf("%s",map[i]+1);来输入 39 for (int i = 1; i <= n; i++) 40 gets(map[i] + 1); 41 ans = 0; 42 dfs(1, 1, 0); 43 printf("%d\n", ans); 44 } 45 return 0; 46 }
G:G和C几乎一模一样,就不解释了:
代码: 31MS
1 #include2 #include 3 #include 4 using namespace std; 5 int number,quan,N,x1,y1,z1,x2,y2,z2; 6 const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}}; 7 char a[30][30][30]; 8 class K 9 { 10 public: 11 int x,y,z,step; 12 }k[1000000]; 13 void bfs(int z,int x,int y) 14 { 15 int f=0,r=1,i,hx,hy,hz; 16 memset(k,0,sizeof(k)); 17 k[0].x=x; 18 k[0].y=y; 19 k[0].z=z; 20 k[0].step=0; 21 a[z][x][y]='X'; 22 while(f<r) 23 { 24 for(i=0;i<6;i++) 25 { 26 hx=k[f].x+add[i][0]; 27 hy=k[f].y+add[i][1]; 28 hz=k[f].z+add[i][2]; 29 30 if(hx>=0 && hx =0 && hy =0 && hz 'O') 31 { 32 if(hz==z2 && hx==x2 && hy==y2) 33 {number=k[f].step+1; return;} 34 k[r].x=hx; 35 k[r].y=hy; 36 k[r].z=hz; 37 k[r++].step=k[f].step+1; 38 a[hz][hx][hy]='X'; 39 } 40 } 41 f++; 42 } 43 return; 44 } 45 46 int main() 47 { 48 char w[4],q[10]; 49 while(~scanf("%s",q)) 50 { 51 scanf("%d",&N); 52 int i,j,k; 53 memset(a,0,sizeof(a)); 54 for(i=0;i ) 55 { 56 for(j=0;j ) 57 scanf("%s",a[i][j]); 58 } 59 scanf("%d%d%d",&z1,&x1,&y1); 60 scanf("%d%d%d",&z2,&x2,&y2); 61 scanf("%s",w); 62 quan=0; 63 if(a[z2][x2][y2]=='O') quan++; 64 if(a[z2][x2][y2]=='X') {a[z2][x2][y2]='O';quan--;} 65 number=0; 66 if(z1==z2 && x1==x2 && y1==y2) {printf("%d 0\n",quan);continue;} 67 bfs(z1,x1,y1); 68 if(number==0) 69 printf("NO ROUTE\n"); 70 else 71 printf("%d %d\n",number+quan,number); 72 } 73 return 0; 74 }