Collect More Jewels

原题:hdoj 1044

原题大意

在能走出迷宫的情况下,收集最大价值的珠宝,’*’是墻,’.’表示可以走的空地,’@’表示起点,’<’表示终点,’A-J’用来表示各种价值的珠宝.

算法分析

这题百度了下,我能用的方法就是bfs加dfs,先用bfs算出出口,入口,珠宝之间的两两最短距离,然后再用dfs遍历每条从起点到终点的路径.

注意事项

这题我一开始交的时候总是超时,后来百度了下,在dfs里加了段代码,作用是如果收集的珠宝已达到所有珠宝价值之和,递归就结束.(这是我第一次超时,下次再出现时要考虑清楚哪里可以缩短时间)

程序代码

#include <iostream>
#include <queue>
#include <memory.h>
using namespace std;
int W,H,L,M;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
char g[50][50];
int len[12][12];//宝物,出入口的两两距离 
int l[50][50];//记录距离 
bool used[12];//dfs剪枝 
bool visit[50][50]; //bfs剪枝
int val[12];//宝物价值 
int a[13];//宝物,出入口的坐标 
int maxval=0;
queue<int> q;
void bfs(int x1,int y1,int n)
{
    while(!q.empty()) q.pop();
    q.push(a[n]);
    visit[x1][y1]=1;
    while(!q.empty())
    {

        int t=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xx,yy;
            xx=x1+dx[i];
            yy=y1+dy[i];
            if(xx<0||xx>=H||yy<0||yy>=W) continue;
            if(g[xx][yy]=='*'||visit[xx][yy]) continue;

            visit[xx][yy]=true;
            l[xx][yy]=l[x1][y1]+1;
            int mm;
            if(g[xx][yy]=='.')
            {
                q.push(xx*W+yy);
                continue;
            }
            if(g[xx][yy]=='@') mm=0;
            if(g[xx][yy]=='<') mm=M+1;
            else mm=g[xx][yy]-'A'+1;
            len[n][mm]=l[xx][yy];
            q.push(xx*W+yy);
        } 
    }    
}
void dfs(int s,int time,int value)
{
    if(time>L) return ;
    if(s==M+1)
    {
        if(value>maxval)
            maxval=value;
        return ;
    }
    for(int i=1;i<=M+1;i++)        //与for(int i=1;i<=M+1&&!used[i];i++)
    {                            // 不同 
        if(used[i]) continue;    
        used[i]=1;
        dfs(i,time+len[s][i],value+val[i]);
        used[i]=0;
    }

}
int main()
{
    int r;
    scanf("%d",&r);
    for(int Case=1;Case<=r;Case++)
    {
        printf("\n");
        scanf("%d%d%d%d",&W,&H,&L,&M);
        for(int i=1;i<=M;i++)
            scanf("%d",&val[i]);
        val[0]=val[M+1]=0;
        for(int i=0;i<H;i++)
            scanf("%s",g[i]); 
        for(int i=0;i<H;i++)
            for(int j=0;j<W;j++)
                {
                    if(g[i][j]=='@') a[0]=i*W+j;
                    if(g[i][j]=='<')
                    {
                         a[M+1]=i*W+j;
                    }
                    if(g[i][j]>='A'&&g[i][j]<='A'+10)
                        a[g[i][j]-'A'+1]=i*W+j;
                }
        for(int i=0;i<=M+1;i++)
        {
            memset(visit,0,sizeof(visit));
            memset(l,0,sizeof(l));
            bfs(a[i]/W,a[i]%W,i);
        }
        memset(used,0,sizeof(used));
        dfs(0,0,0); 
        if(maxval==0)
            printf("Case %d:\nImpossible\n",Case);
        else
            printf("Case %d:\nThe best score is %d\n",Case,maxval);
        maxval=0;
    }
    return 0;
}