HDU 1044

题意:

勇士走迷宫,迷宫是个大小为H*W的矩阵图。其中'@'代表起点,'<'代表终点,'A'-'J'代表宝物点(有权值),'*'代表墙。勇士的目标是在限定时间内的,在走出迷宫的前提下,获得的宝物价值和最大。

输入:首先一个整数T,代表case数。

对于每个case,首先输入四个数W (1 <= W <= 50), H (1 <= H <= 50), L (1 <= L <= 1,000,000) and M (1 <= M <= 10)。 接下来M个整数,代表宝物的价值。然后就输入迷宫地图(H*W)。

输出:若无法走出迷宫,输出Impossible。可以走出时,请输出可以获得的宝物价值和的最大值。


题解:一道状压的题目。重点在于将原始矩阵图中的起点、终点、宝物点提取出来(总共最多就12个),建立它们之间的有权无向图,其中任意两点之间的边的权重值为这两点在原始矩阵图中的最短距离。然后利用这张图我们建立如下状态转移公示:dp[st|(1<<k)][k]=max(dp[st|(1<<k)][k],max(dp[st][e]+dis[k][e]) );其中k是新状态中我们走到的最后一个点,e是前一状态我们走到的最后一个点。最后记住输出格式,要求每两个案例中有个空行,最后一个不用空行。


代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#define ll long long
using namespace std;
const int inf=0x08080808;
const int maxn=1<<14;
int W,H,L,M;
int val[14],dis[14][14],vis[60][60],dist[60][60];
int dp[maxn][14];
char mp[60][60];
int op[4][2]={-1,0,1,0,0,1,0,-1};
struct Position{
    int x,y;
}pos[10];
queue<int>qx,qy;
bool is_norm(int x,int y,int m){
    if(x+op[m][0]>=0&&x+op[m][0]<H&&y+op[m][1]>=0&&y+op[m][1]<W&&!vis[x+op[m][0]][y+op[m][1]]&&mp[x+op[m][0]][y+op[m][1]]!='*')
        return true;
    return false;
}
void bfs(int s){
    int sx=pos[s].x,sy=pos[s].y;
    while(!qx.empty()) qx.pop(),qy.pop();
    memset(vis,0,sizeof(vis));
    qx.push(sx),qy.push(sy);
    dist[sx][sy]=0;
    while(!qx.empty()){
        int px=qx.front(),py=qy.front();
        qx.pop(),qy.pop();
        for(int i=0;i<4;++i)
            if(is_norm(px,py,i)){
                int nx=px+op[i][0],ny=py+op[i][1];
                dist[nx][ny]=dist[px][py]+1;
                qx.push(nx),qy.push(ny);
                vis[nx][ny]=1;
                if(mp[nx][ny]>='0'&&mp[nx][ny]<='0'+M+1){
                    int e=mp[nx][ny]-'0';
                    dis[s][e]=dist[nx][ny];
                }
            }
    }
}
int main(){
    int T;
    scanf("%d",&T);
    int kase=0;
    while(T--){
        scanf("%d%d%d%d",&W,&H,&L,&M);
        for(int i=1;i<=M;++i) scanf("%d",&val[i]);
        for(int i=0;i<H;++i)
        for(int j=0;j<W;++j){
            cin>>mp[i][j];
            if(mp[i][j]=='@') pos[0].x=i,pos[0].y=j,mp[i][j]='0';
            else if(mp[i][j]>='A'&&mp[i][j]<='J') pos[mp[i][j]-'A'+1].x=i,pos[mp[i][j]-'A'+1].y=j,mp[i][j]=mp[i][j]-'A'+'1';
            else if(mp[i][j]=='<') pos[M+1].x=i,pos[M+1].y=j,mp[i][j]='0'+M+1;
        }
        memset(dis,inf,sizeof(dis));
        for(int i=0;i<=M+1;++i) bfs(i);
        memset(dp,inf,sizeof(dp));
        dp[1][0]=0;
        for(int st=1;st<(1<<M+2);++st){
            for(int k=0;k<=M+1;++k){
                if((st&(1<<k))==0){
                    for(int e=0;e<=M+1;++e)
                    if(dp[st|(1<<k)][k]>dp[st][e]+dis[e][k]){
                        dp[st|(1<<k)][k]=dp[st][e]+dis[k][e];
                    }
                }
            }
        }
        int ans=-1;
        for(int i=0;i<(1<<M+2);++i){
            int temp=0;
            for(int k=1;k<=M;++k){
                if(i&(1<<k)) temp+=val[k];
            }
            if(temp>ans&&dp[i][M+1]<=L)
                ans=temp;
        }
        printf("Case %d:\n",++kase);
        if(ans==-1)
            printf("Impossible\n");
        else
            printf("The best score is %d.\n",ans);
        if(T) printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值