第三次组队赛 (DFS&BFS)
2013-08-01 22:55
260 查看
网站: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
B 大意是:找出最大的湖泊的格子数,只能上下左右,对角不算相连 Avoid The Lakes POJ 3620
代码: 16ms BFS
另一种方法:DFS 16MS
C 大意是:一个Z层x*y的楼房,要从起点到中点,问最少要走多少步? 6个方向 Dungeon Master POJ 2251
代码: 0MS
D 大意是:给出一个数m,要用n个数来凑,这n个数分别是a1,a2,a3a.....an.输出加法式 Sum It Up HDU 1258
代码: 15MS
另一份代码: 0ms
E大意是:在N*N的棋盘上放N个皇后,每两个皇后不能在同一行,同一列,也不能再同一斜线上(45°斜线),问有多少种方法?
这一道题我们是水过去的,因为规定了N<=10,所以只有10种情况,一一列举出来。╮(╯▽╰)╭
以下解释&&代码来自http://blog.sina.com.cn/s/blog_696187fd0100p5ri.html# (我修改了一些地方)
方法一: 递归回溯 //会超时......
方法二:迭代回溯 可以理解但是....他是肿么想出来的.....其实和上面那个方法差不多,但是不是用递归实现的
这样用记忆法才不会超时 15MS
E 大意是:找出棋盘上最多能放的棋子数,不能同一行同一列(隔开了就可以),允许在同一斜线上。
如图:
1:棋盘。2:正确的方法(也是最多的),3正确,4&5错误.
和N皇后有点像,指不过斜线也可以放,而且有墙,隔开也可以放。
代码: 来自:http://blog.csdn.net/hcbbt/article/details/9420387 15MS,头文件加上#include<iostream> using namespace std;之后时间为0MS
G:G和C几乎一模一样,就不解释了:
代码: 31MS
先总结下,不得不说死的很惨,又是第三就不说了,一共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
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; int map[30][30],x[30],y[30]; int d[8][2]={{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},{1, -2}, {1, 2}, {2, -1}, {2, 1}}; //字典序 int m,n,sign,step; void dfs(int i,int j) { int a,b,k; if(sign) //以历遍,跳出 return ; step++; x[step]=i; //当前位置 y[step]=j; if(step==m*n) //步数=格子数 { sign=1; return ; } map[i][j]=1; //标记 for(k=0;k<8;k++) { b=j+d[k][0]; //注意 a=i+d[k][1]; if(map[a][b]==0 && a>0 && b>0 && a<=m && b<=n) { dfs(a,b); step--; //不符合要求是回溯步数 } } map[i][j]=0; //返回 } int main() { int T,i,t=0; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&n); t++; memset(map,0,sizeof(map)); step=0; sign=0; dfs(1,1); printf("Scenario #%d:\n", t); if(sign) { for(i=1;i<=m*n;i++) printf("%c%d",y[i]+64,x[i]); //注意这里,先是y,再是x printf("\n\n"); //要空一行 } else printf("impossible\n\n"); //要空一行 } return 0; }
B 大意是:找出最大的湖泊的格子数,只能上下左右,对角不算相连 Avoid The Lakes POJ 3620
代码: 16ms BFS
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int d[4][2]={{1,0},{0,1},{0,-1},{-1,0}}; int map[105][105]; int m,n; class A { public: int a; int b; }; A q[10025]; void bfs() { A r,t; int i,j,ans,k,maxn=0; for(j=1;j<=m;j++) //扫描 for(k=1;k<=n;k++) { if(map[j][k]==1) { ans=1; int g=0; int h=0; map[j][k]=0; //标记 q[g].a=j; //开始的位置 q[g].b=k; g++; while(h!=g) { r=q[h++]; for(i=0;i<4;i++) { t.a=r.a+d[i][0]; t.b=r.b+d[i][1]; if(t.a>0 && t.a<=m && t.b>0 && t.b<=n && map[t.a][t.b]==1) //满足条件 { q[g++]=t; map[t.a][t.b]=0; //标记 ans++; } } } if(maxn<ans) //找出最大值 maxn=ans; } } cout<<maxn<<endl; } int main() { int i,j,k,x; memset(map,0,sizeof(map)); while(~scanf("%d%d%d",&m,&n,&x)) { for(i=0;i<x;i++) { scanf("%d%d",&j,&k); map[j][k]=1; } bfs(); } return 0; }
另一种方法:DFS 16MS
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> using namespace std; int b[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; int a[105][105]; int n,m,s; void dfs(int i,int j) { int k,x,y; s++; a[i][j]=0; //标记 for(k=0;k<4;k++) { x=i+b[k][0]; y=j+b[k][1] ; if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]==1) //满足条件 dfs(x,y); } } int main() { int t,a1,b1,i,j,MAX; while(~scanf("%d%d%d",&n,&m,&t)) { s=0; memset(a,0,sizeof(a)); for(i=0;i<t;i++) { scanf("%d %d",&a1,&b1); a[a1][b1]=1; } MAX=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) // 遍历能够开始的点 if(a[i][j]==1) { dfs(i,j); if(s>MAX) //找到最大值 MAX=s; s=0; } printf("%d\n",MAX); } return 0; }
C 大意是:一个Z层x*y的楼房,要从起点到中点,问最少要走多少步? 6个方向 Dungeon Master POJ 2251
代码: 0MS
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int number,Z,X,Y,x1,y1,z1,x2,y2,z2; const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}}; //上下左右前后6个方向 char a[30][30][30]; class K { public: int x,y,z,step; }k[1000000]; void bfs(int z,int x,int y) { int f=0,r=1,i,hx,hy,hz; k[0].x=x; //开始位置 k[0].y=y; k[0].z=z; k[0].step=0; a[z][x][y]='#'; //标记 while(f<r) { for(i=0;i<6;i++) { hx=k[f].x+add[i][0]; hy=k[f].y+add[i][1]; hz=k[f].z+add[i][2]; if(hx>=0 && hx<X && hy>=0 && hy<Y && hz>=0 && hz<Z && (a[hz][hx][hy]=='.' ||a[hz][hx][hy]=='E') ) { if(a[hz][hx][hy]=='E') {number=k[f].step+1; return;} k[r].x=hx; k[r].y=hy; k[r].z=hz; k[r++].step=k[f].step+1; a[hz][hx][hy]='#'; } } f++; } return; } int main() { while(scanf("%d%d%d",&Z,&X,&Y)&&Z&&Y&&X) { int i,j,k; memset(a,0,sizeof(a)); for(i=0;i<Z;i++) //输入地图 for(j=0;j<X;j++) scanf("%s",a[i][j]); for(i=0;i<Z;i++) for(j=0;j<X;j++) for(k=0;k<Y;k++) if(a[i][j][k]=='S') //起点 { x1=j; y1=k; z1=i; } number=0; bfs(z1,x1,y1); if(number==0) printf("Trapped!\n"); else printf("Escaped in %d minute(s).\n",number); } return 0; }
D 大意是:给出一个数m,要用n个数来凑,这n个数分别是a1,a2,a3a.....an.输出加法式 Sum It Up HDU 1258
代码: 15MS
#include<stdio.h> 2 int t,n,flag,a[20],b[20]; void dfs(int j,int k,int g)
{ int i; if(j>t) return ; if(j==t) //凑成了t { flag=0; //至少有一种凑的方法 for(i=0;i<g-1;i++) printf("%d+",b[i]); printf("%d\n",b[g-1]); //打出等式 return ; } int last=-1; for(i=k;i<n;i++) //和每个排在自己之后的数加一次 { if(j+a[i]>t) //超过就跳过 continue; if(a[i]!=last) //不等于最后加的一个数,否则等式一样 22 { last=b[g]=a[i]; //更新最后加的数 dfs(j+a[i],i+1,g+1); } } } int main() { int i; while(~scanf("%d%d",&t,&n)&&n&&t) { flag=1; for(i=0;i<n;i++) scanf("%d",&a[i]); printf("Sums of %d:\n",t); dfs(0, 0, 0); if(flag) printf("NONE\n"); } }
另一份代码: 0ms
#include <stdio.h> #include<string.h> const int N=20; int a ,n,t,flag; bool vis ; void print() { flag=1; bool bol=0; int i; for (i=1;i<=n;i++) if (vis[i]) //判断要不要加 { if (bol) printf("+%d",a[i]); else {bol=1; printf("%d",a[i]);} //加的第一个数 } printf("\n"); } void dfs(int s,int p) { if (s==t) {print(); return;} int i; for (i=p+1;i<=n;i++) //s和最后一个加数之后所有的数加一次 { vis[i]=1; //标记,代表加了这个数 if (s+a[i]<=t) dfs(s+a[i],i); vis[i]=0; //不满足则退回到上一步 while (i<=n && a[i]==a[i+1]) //一样的数不用再加,否则会重复 i++; } } int main() { int i; while (scanf("%d%d",&t,&n),n||t) { flag=0; for (i=1;i<=n;i++) scanf("%d",&a[i]); printf("Sums of %d:\n",t); dfs(0,0); if (!flag) printf("NONE\n"); } return 0; }
E大意是:在N*N的棋盘上放N个皇后,每两个皇后不能在同一行,同一列,也不能再同一斜线上(45°斜线),问有多少种方法?
这一道题我们是水过去的,因为规定了N<=10,所以只有10种情况,一一列举出来。╮(╯▽╰)╭
以下解释&&代码来自http://blog.sina.com.cn/s/blog_696187fd0100p5ri.html# (我修改了一些地方)
方法一: 递归回溯 //会超时......
#include<stdio.h> #include<math.h> #define N 15 int n; //皇后个数 int sum = 0; //可行解个数 int x ; //皇后放置的列数 int place(int k) { int i; for(i=1;i<k;i++) 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]在同一列 return 0; return 1; } int queen(int t) { if(t>n) //当放置的皇后超过n时,可行解个数加1 sum++; else for(int i=1;i<=n;i++) { x[t] = i; //标明第t个皇后放在第i列 if(place(t)) //如果可以放在某一位置,则继续放下一皇后 queen(t+1); } return sum; } int main() { while(~scanf("%d",&n)&&n) { sum=0; int t = queen(1); printf("%d\n",t); } return 0; }
方法二:迭代回溯 可以理解但是....他是肿么想出来的.....其实和上面那个方法差不多,但是不是用递归实现的
#include<stdio.h> #include<math.h> #define N 15 int n; int sum = 0; int x ; int place(int k) //判断能不能放这~~~ { int i; for(i=1;i<k;i++) 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]是在同一列上 return 0; return 1; } int queen() { x[1] = 0; int t=1; while(t>0) { x[t]+=1; while(x[t]<=n && !place(t)) //一列列试,不行则放下一列 x[t]++; if(x[t]<=n ) if(t==n) sum++; else x[++t] = 0; else t--; //满了则退回一步 } return sum; } int main() { int t; while(~scanf("%d",&n),n) { sum=0; t = queen(); printf("%d\n",t); } return 0; }
这样用记忆法才不会超时 15MS
#include <stdio.h> #include <iostream> #include <math.h> using namespace std; int n,x[15],sum,a[15]; int place(int i) { for(int j=1;j<i;j++) if(fabs(i-j)==fabs(x[i]-x[j]) || x[i]==x[j]) return 0; return 1; } int qeen(int i) { if(i>n) sum++; else for(int j=1;j<=n;j++) { x[i]=j; if(place(i)) qeen(i+1); } return sum; } int main() { for(n=1;n<=10;n++) { sum=0; a =qeen(1); } while(~scanf("%d",&n)&&n) printf("%d\n",a ); return 0; }
E 大意是:找出棋盘上最多能放的棋子数,不能同一行同一列(隔开了就可以),允许在同一斜线上。
如图:
1:棋盘。2:正确的方法(也是最多的),3正确,4&5错误.
和N皇后有点像,指不过斜线也可以放,而且有墙,隔开也可以放。
代码: 来自:http://blog.csdn.net/hcbbt/article/details/9420387 15MS,头文件加上#include<iostream> using namespace std;之后时间为0MS
#include <cstdio> const int maxn = 5; char map[maxn][maxn]; int ans, n; bool isok(int x, int y) { for (int i = x + 1; i <= n && map[i][y] != 'X'; i++) //遇到'X'就不再搜了 if(map[i][y] == '0') return false; for (int i = x - 1; i >= 1 && map[i][y] != 'X'; i--) if(map[i][y] == '0') return false; for (int i = y + 1; i <= n && map[x][i] != 'X'; i++) if (map[x][i] == '0') return false; for (int i = y - 1; i >= 1 && map[x][i] != 'X'; i--) if (map[x][i] == '0') return false; return true; } void dfs(int x, int y, int p) { for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (map[i][j] == '.' && isok(i, j)) { map[i][j] = '0'; //代表已经放了一颗棋子 dfs(i, j, p + 1); map[i][j] = '.'; } if (ans < p) ans = p; } int main() { while (scanf("%d", &n) && n) { gets(map[0]); //可改成用scanf("%s",map[i]+1);来输入 for (int i = 1; i <= n; i++) gets(map[i] + 1); ans = 0; dfs(1, 1, 0); printf("%d\n", ans); } return 0; }
G:G和C几乎一模一样,就不解释了:
代码: 31MS
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int number,quan,N,x1,y1,z1,x2,y2,z2; const int add[6][3]={{0,1,0},{0,-1,0},{1,0,0},{-1,0,0},{0,0,1},{0,0,-1}}; char a[30][30][30]; class K { public: int x,y,z,step; }k[1000000]; void bfs(int z,int x,int y) { int f=0,r=1,i,hx,hy,hz; memset(k,0,sizeof(k)); k[0].x=x; k[0].y=y; k[0].z=z; k[0].step=0; a[z][x][y]='X'; while(f<r) { for(i=0;i<6;i++) { hx=k[f].x+add[i][0]; hy=k[f].y+add[i][1]; hz=k[f].z+add[i][2]; if(hx>=0 && hx<N && hy>=0 && hy<N && hz>=0 && hz<N && a[hz][hx][hy]=='O') { if(hz==z2 && hx==x2 && hy==y2) {number=k[f].step+1; return;} k[r].x=hx; k[r].y=hy; k[r].z=hz; k[r++].step=k[f].step+1; a[hz][hx][hy]='X'; } } f++; } return; } int main() { char w[4],q[10]; while(~scanf("%s",q)) { scanf("%d",&N); int i,j,k; memset(a,0,sizeof(a)); for(i=0;i<N;i++) { for(j=0;j<N;j++) scanf("%s",a[i][j]); } scanf("%d%d%d",&z1,&x1,&y1); scanf("%d%d%d",&z2,&x2,&y2); scanf("%s",w); quan=0; if(a[z2][x2][y2]=='O') quan++; if(a[z2][x2][y2]=='X') {a[z2][x2][y2]='O';quan--;} number=0; if(z1==z2 && x1==x2 && y1==y2) {printf("%d 0\n",quan);continue;} bfs(z1,x1,y1); if(number==0) printf("NO ROUTE\n"); else printf("%d %d\n",number+quan,number); } return 0; }
相关文章推荐
- 第三次组队赛(bfs&&dfs)
- lightoj Winter 1084 (dfs&&bfs求最少堆数) 好题
- POJ_S1E03_DFS&BFS(1)
- [LeetCode] Clone Graph(!!!!graph&dfs&bfs)
- DFS&BFS入门
- DFS&BFS
- poj 1979DFS&&BFS
- Clone Graph BFS & DFS
- POJ_S1E03_DFS&BFS(3)
- KNOW: BFS & DFS
- 算法学习笔记(一):拓扑排序与传递闭包(通过bfs&&dfs)
- BFS & DFS的基础学习
- DFS & BFS
- hdu1241 Oil Deposits(dfs&&bfs)
- HDOJ 1181 变形课 DFS & BFS & Floyd
- 图的遍历(最小转机数)——dfs&&bfs
- 【HDUOJ1241】bfs&&dfs
- hdu1254(bfs&&dfs)
- Graph Algorithms: Implementation& DFS& Strong Component& BFS & Dijkstra & Bellman Ford
- HDOJ 1254 推箱子【bfs && dfs】