HDU 1044 [Collect More Jewels] DFS+BFS
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1044
题目大意:在地图中,有M个宝石,每个宝石有不同价值。问在时间限制L之内,从入口到出口这一路上获得的最大价值是多少。拿宝石不额外花时间,走一格用时为1.
关键思想:考虑到BFS和DFS的特点,BFS在解决最短(小)问题是很有效,但内存耗费巨大;DFS可以解决绝大多数搜索问题,但层数较深时,时间开销和栈的开销都很大。
这道题,只用DFS显然是不行的,地图比较大了。但是只用BFS也不行,因为取完之后地图状态会发生改变,考虑这样一种情况,如果终点邻近处有一个宝石,那当你时间多的时候,是会跨过终点取完宝石再回来的。只用一种搜索不行,那两种搜索并用吧。
我们先用BFS把起点、终点、各个宝石这些重要元素之间的最短用时解出来。(只有10多个)
然后用DFS搜索从起点经过重要元素到达终点的最大收益。好好想一想为什么可以这样算,你一定能理解。
代码如下:
#include <iostream> #include <memory.h> #include <stdio.h> #include <queue> using namespace std; const int INF=1e8; const int MAXN=55; const int MAXM=16; char m[MAXN][MAXN]; int dir[4][2]={0,1,1,0,0,-1,-1,0}; int W,H,L,M,sum,ans;//L时限 struct node{ int x,y; int t; };//[0]为起点,[T+1]为终点 int v[MAXM];//0不用 int newM[MAXM][MAXM];//构造出来的邻接矩阵 ,将重要元素作为点 bool vis[MAXM];//DFS的时候用到 bool vis2[MAXN][MAXN];//BFS的时候用到 ,这样不会爆空间 void dfs(int p0,int money,int time){ if(ans==sum||time>L)return;//sum这个优化很关键,TLE和AC的差别 if(p0==M+1){//如果到了终点,更新当前获得的钱 ans=max(ans,money); } for(int i=1;i<=M+1;i++){ if(!vis[i]){ vis[i]=true; dfs(i,money+v[i],time+newM[p0][i]); vis[i]=false; } } return; } void bfs(int x,int y,int from){//bfs计算重要元素间的最短时间 memset(vis2,0,sizeof(vis2)); queue<node>q; node nw,nt; vis2[x][y]=true; nw.x=x,nw.y=y,nw.t=0; q.push(nw); while(!q.empty()){ nw=q.front(); q.pop(); for(int i=0;i<4;i++){ nt.x=nw.x+dir[i][0]; nt.y=nw.y+dir[i][1]; nt.t=nw.t+1; if(!vis2[nt.x][nt.y]&&nt.x>=1&&nt.x<=H&&nt.y>=1&&nt.y<=W&&m[nt.x][nt.y]!='*'&&nt.t<=L){//可以走的路径 if(m[nt.x][nt.y]<='Z'&&m[nt.x][nt.y]>='A'&&newM[from][m[nt.x][nt.y]-'A'+1]==INF){//如果找到重要的点就更新最短时间,加了一点优化 newM[from][m[nt.x][nt.y]-'A'+1]=nt.t; newM[m[nt.x][nt.y]-'A'+1][from]=nt.t; } else if(m[nt.x][nt.y]=='@'&&newM[from][0]==INF){ newM[from][0]=nt.t; newM[0][from]=nt.t; } else if(m[nt.x][nt.y]=='<'&&newM[from][M+1]==INF){ newM[from][M+1]=nt.t; newM[M+1][from]=nt.t; } vis2[nt.x][nt.y]=1; q.push(nt); } } } return; } int main(){ int T; scanf("%d",&T); for(int cnt=1;cnt<=T;cnt++){ memset(vis,0,sizeof(vis)); memset(newM,-1,sizeof(newM)); scanf("%d%d%d%d",&W,&H,&L,&M); ans=-1; sum=0;//sum保存宝石总价值 for(int i=1;i<=M;i++){scanf("%d",&v[i]);sum+=v[i];} v[M+1]=0; //要注意,DFS会涉及 ,终点没有宝石 for(int i=1;i<=H;i++){ for(int j=1;j<=W;j++){ scanf(" %c",&m[i][j]); } } //新图的邻接矩阵初始化 for(int i=0;i<=M+1;i++){ for(int j=0;j<=M+1;j++){ if(i!=j)newM[i][j]=INF; else newM[i][j]=0; } } //开始BFS获得重要元素间的最少耗时,要用到坐标i、j for(int i=1;i<=H;i++){ for(int j=1;j<=W;j++){ if(m[i][j]<='Z'&&m[i][j]>='A'){ bfs(i,j,m[i][j]-'A'+1); } else if(m[i][j]=='@'){ bfs(i,j,0); } else if(m[i][j]=='<'){ bfs(i,j,M+1); } } } printf("Case %d:\n",cnt); //newM[0][M+1]<=L if(newM[0][M+1]<=L){//如果起点到终点最短距离都大于L那肯定不行 dfs(0,0,0); printf("The best score is %d.\n",ans); } else printf("Impossible\n"); if(cnt!=T)printf("\n"); } return 0; }
边完善自己边认识自己