杭电1044题Collect More Jewels:http://acm.hdu.edu.cn/showproblem.php?pid=1044 算法思想:先用bfs建立一张起点、终点、珠宝点之间的距离的无向图,再用dfs找出能取得的最大的值
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
int x; int y; int time;
node(int a,int b,int c):x(a),y(b),time(c){}
};
int W,H,L,M,ans,vals;
char maze[55][55]; //输入的字符矩阵
bool vis[55][55]; //字符的访问矩阵
int graph[15][15]; //建立的距离虚图
int jewel[15]; //起点、终点、珠宝点的价值数组
bool isUsed[15]; //起点、终点、珠宝店的访问数组
int dx[4]={0,1,0,-1};//上下方向的数组
int dy[4]={-1,0,1,0};//左右方向的数组
void bfs(int x1,int y1) //广搜,建立一张虚图,起点、终点、珠宝点两两之间距离的图
{
memset(vis,false,sizeof(vis));
int u,v; //u为当前点的价值,v为下一个点的价值
char a=maze[x1][y1]; //取出当前字符
if(a=='@') u=0;
if(a>='A'&&a<='J') u=a-'A'+1;
node pos(0,0,0),nextpos(0,0,0); //当前点,下一步的点
pos.x=x1; pos.y=y1; pos.time=0;
queue<node>Q;
Q.push(pos); vis[pos.x][pos.y]=true;
while(!Q.empty())
{
pos=Q.front(); Q.pop();
if(pos.time==L) break; //优化操作
for(int i=0;i<4;i++)
{
nextpos.x=pos.x+dx[i]; nextpos.y=pos.y+dy[i]; nextpos.time=pos.time+1;
// 如果为墙壁或者访问过,跳过
if(maze[nextpos.x][nextpos.y]=='*'||vis[nextpos.x][nextpos.y]) continue;
//如果超出矩阵的范围,跳过
if(nextpos.x<0||nextpos.x>=H||nextpos.y<0||nextpos.y>=W) continue;
vis[nextpos.x][nextpos.y]=true; //设置为访问过
if(maze[nextpos.x][nextpos.y]=='@') //如果为起点
graph[u][0]=graph[0][u]=nextpos.time;
else if(maze[nextpos.x][nextpos.y]=='<') //如果为终点
graph[u][M+1]=graph[M+1][u]=nextpos.time;
else if(maze[nextpos.x][nextpos.y]>='A'&&maze[nextpos.x][nextpos.y]<='J')
{ //如果为珠宝点
v=maze[nextpos.x][nextpos.y]-'A'+1; //取得珠宝的价值
graph[u][v]=graph[v][u]=nextpos.time;
}
Q.push(nextpos); //加入队列
}
}
}
void dfs(int index,int limit,int je) //对虚图进行深搜
{ //index当前点的下标,limit为当前走过的时间,je为当前取得的价值和
if(limit>L) return; //超过时间范围,结束,ans为初始值-1
if(ans==vals) return; //没超过时间范围的前提下,已取得所有珠宝的总价值,
if(index==M+1) //到达出口
{
if(je>ans) ans=je; //如果当前取得的珠宝价值大于ans的-1,结束
return;
}
for(int i=1;i<=M+1;i++) //深搜
{
if(isUsed[i]||graph[index][i]==0) continue; //访问过,或者无法到达,continue掉
isUsed[i]=true; //访问过
dfs(i,limit+graph[index][i],je+jewel[i]);
isUsed[i]=false; //回溯
}
}
int main()
{
int t;
cin>>t;
for(int tt=1;tt<=t;tt++)
{
ans=-1; vals=0;
cin>>W>>H>>L>>M;
for(int i=1;i<=M;i++)
{
cin>>jewel[i]; //输入珠宝数组
vals+=jewel[i]; //求出珠宝的价值和是为了深搜的剪枝
}
jewel[0]=jewel[M+1]=0; //初始化起点和终点的价值为0
for(int i=0;i<H;i++)
cin>>maze[i]; //输入迷宫数组
memset(graph,0,sizeof(graph)); //初始化虚图,无法到达时间距离为0
for(int i=0;i<H;i++)
for(int j=0;j<W;j++)
{ //起点要合法,只允许起点和珠宝点进行广搜
if(maze[i][j]=='@'||(maze[i][j]>='A'&&maze[i][j]<='J'))
bfs(i,j); //建立起点、终点、珠宝点的两两之间距离的虚图
}
memset(isUsed,false,sizeof(isUsed));//初始化深搜的访问数组
isUsed[0]=true;
dfs(0,0,0);
cout<<"Case "<<tt<<":\n";
if (ans == -1) cout << "Impossible\n";
else cout << "The best score is " << ans << ".\n";
if (tt != t) cout << endl;
}
}