题目:poj 2488 A Knight's Journey
题意:
给一个m*n的棋盘,马走日,给出一条字典序最小的马的路线来走完整个棋盘?
分析:
如果能走完棋盘,那么从(1,1)点dfs即可,因为他能走完整个棋盘嘛,总有一步会经过(1,1),所以从(1,1)出发就能到其他所有点。
为了保证字典序,在枚举方向时顺序要保证x轴优先,然后y轴。
#include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<algorithm> using namespace std; const int N=33; typedef pair<int,int>pii; vector<pii>ans; int dx[][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}}; int n,m; bool vis[N][N]; bool dfs(int x,int y,int step) { if(step==n*m)return 1; for(int i=0;i<8;i++){ int xx=dx[i][0]+x; int yy=dx[i][1]+y; if(xx<1||yy<1||xx>n||yy>m||vis[xx][yy])continue; vis[xx][yy]=1; ans.push_back(make_pair(xx,yy)); if(dfs(xx,yy,step+1)) return 1; vis[xx][yy]=0; ans.pop_back(); } return 0; } int main() { int T;scanf("%d",&T); for(int cas=1;cas<=T;cas++){ ans.clear(); scanf("%d%d",&m,&n); ans.push_back(make_pair(1,1)); memset(vis,0,sizeof(vis)); vis[1][1]=1; printf("Scenario #%d: ",cas); if(dfs(1,1,1)){ for(int i=0;i<ans.size();i++) printf("%c%d",(char)('A'+ans[i].first-1),ans[i].second); } else printf("impossible"); printf(" "); } return 0; }
题目:poj 3009
题意:
滚小球,小球刚开始在起点S,每次可以往四个方向扔出,扔出后小球一直滚动,直到碰到砖块(砖块碰到后消失)或者到达终点E。问小球到E的最短路?
分析:
虽然是到类似于最短路的题目,但是似乎bfs是不行的,因为每次球发生碰撞后会改变地图,有可能出现更优解!所以要dfs找出所有的可能解(所以数据范围才小),但是要剪枝,不然会超时。
#include<cstdio> using namespace std; const int INF=0x3f3f3f3f; const int N=22; int g[N][N]; int w,h,sx,sy; int dx[][2]={{-1,0},{1,0},{0,-1},{0,1}}; int ans=INF; void dfs(int x,int y,int step) { if(step>=10||step>=ans)return; //剪枝 for(int i=0;i<4;i++){ int xx=dx[i][0]+x; int yy=dx[i][1]+y; if(g[xx][yy]==1)continue; while(xx>=0&&xx<w&&yy>=0&&yy<h&&g[xx][yy]!=1&&g[xx][yy]!=3)xx=dx[i][0]+xx,yy=dx[i][1]+yy; if(xx<0||xx==w||yy<0||yy==h)continue; if(g[xx][yy]==3){ans=step+1;return;} //每次更新,一定更优,因为上面已经剪过枝 g[xx][yy]=0; dfs(xx-dx[i][0],yy-dx[i][1],step+1); g[xx][yy]=1; } } int main() { while(~scanf("%d%d",&w,&h)&&(w+h)){ ans=INF; for(int j=0;j<h;j++) for(int i=0;i<w;i++){ scanf("%d",&g[i][j]); if(g[i][j]==2)sx=i,sy=j; } dfs(sx,sy,0); if(ans==INF)printf("-1 "); else printf("%d ",ans); } return 0; }
题目:poj 1321
题意:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
分析:
要找所有方案,显然是要dfs找出所有可能解。因为放了的棋子不能在同一行或者同一列,很容易想到开两个数组标记一下有棋子的行和列,但是这似乎还不能解决这个问题,因为可能出现重复(比如这种方案是AB两点,另一种方案是BA两点),为了防止重复,可以逐行枚举,这样就不会出现重复的情况了。
#include<cstdio> #include<cstring> using namespace std; const int N=10; int n,k; bool visy[N],g[N][N]; char s[N]; int ans; void dfs(int row,int step) { if(step==k){ ans++;return; } for(int i=row;i<n;i++) for(int j=0;j<n;j++){ if(g[i][j]&&!visy[j]){ visy[j]=1; dfs(i+1,step+1); visy[j]=0; } } } int main() { while(~scanf("%d%d",&n,&k)&&(~n)){ memset(visy,0,sizeof(visy)); ans=0; int sx,sy; for(int i=0;i<n;i++){ scanf("%s",s); for(int j=0;j<n;j++) g[i][j]=s[j]=='#'?1:0; } dfs(0,0); printf("%d ",ans); } return 0; }
题目:poj 2251
题意:
给出一个三维的图,求S到E的最短路
分析:
裸的bfs
#include<cstdio> #include<cstring> #include<queue> using namespace std; #define mp make_pair const int N=33; typedef pair<int,int>pii; typedef pair<pii,pii>state; //步数,层,行,列,可能写个struct清晰点QAQ char g[N][N][N]; bool vis[N][N][N]; int C,L,R,sl,sc,sr; //层数,行数,列数,开始的层行列 int d[][3]={{0,0,-1},{0,0,1},{0,-1,0},{0,1,0},{-1,0,0},{1,0,0}}; int bfs() { queue<state>q; q.push(mp(mp(0,sl),mp(sr,sc))); memset(vis,0,sizeof(vis)); vis[sl][sr][sc]=1; while(!q.empty()){ state t=q.front();q.pop(); int step=t.first.first,l=t.first.second,r=t.second.first,c=t.second.second; for(int i=0;i<6;i++){ int tl=l+d[i][0],tr=r+d[i][1],tc=c+d[i][2]; if(tl<0||tl==L||tr<0||tr==R||tc<0||tc==C||vis[tl][tr][tc]||g[tl][tr][tc]=='#')continue; if(g[tl][tr][tc]=='E')return step+1; vis[tl][tr][tc]=1; q.push(mp(mp(step+1,tl),mp(tr,tc))); } } return -1; } int main() { while(~scanf("%d%d%d",&L,&R,&C)&&(L+R+C)){ for(int l=0;l<L;l++) for(int r=0;r<R;r++){ scanf("%s",g[l][r]); for(int c=0;c<C;c++)if(g[l][r][c]=='S')sl=l,sr=r,sc=c; } int t=bfs(); if(t==-1)printf("Trapped! "); else printf("Escaped in %d minute(s). ",t); } return 0; }