HDU 3442 Three Kingdoms 优先队列(非状压做法)

题意:给出一个maze(某三国志类型游戏地图

$ 代表起点

!代表终点

.   代表路

#  代表墙

A,B,C,D,E分别代表不同的防御塔,其射程和攻击力各不相同。但其中只有C是可以走的。且每种防御塔只会造成一次伤害。

求最小伤害,到不了终点惯例输出-1

思路:先用bfs把地图染色,记住每个点都会收到什么伤害,这里用set实现。

再bfs寻路,每个点的所有状态用点集表示(set<set<int> >,set<int>是点集,就是一种状态,而set<set<int> >就是一点的状态集),在bfs时确定同一个点不会有重复的状态被压入队列。

又考虑到状态较多,可能会MLE,使用优先队列,略去多余的状态点。

非状压做法代码:

<span style="font-size:14px;">#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <set>
#include <map>
#include <algorithm>
#include <stack>
using namespace std;
bool vis[60][60];
set <int> maze[60][60];
int dirx[]={0,-1,1,0};
int diry[]={-1,0,0,1};
set <int> em;
typedef struct Node{
    int x;int y;int sum;
    public:
    Node(int xx,int yy,int ss){
        x=xx;y=yy;sum=ss;
    }
}Node;
typedef struct node{
    int x;int y;set <int> s;int ans;
    bool operator < (const node &a)const{
        if(a.ans==ans){
            if(a.x==x)
                return a.y<y;
            return a.x<x;
        }
        return a.ans<ans;
    }
    public:
    node(int xx,int yy,set<int> ss,int a){
        x=xx;y=yy;s=ss;
        a=0;
        set<int>::iterator it;
        for(it=s.begin();it!=s.end();it++)
            a+=*it;
        ans=a;
    }
}node;
const int INF=0x3f3f3f3f;
int n,m,stx,sty,enx,eny;
void bfs(int x,int y,int r,int d){//。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。bfs对图染色
    queue <Node> que;
    que.push(Node(x,y,r));
    bool tvis[60][60]={0};
    tvis[x][y]=1;
    while(!que.empty()){
        Node t=que.front();
        que.pop();
        if(t.sum<0)
            continue;
        else{
            maze[t.x][t.y].insert(d);//。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。一点上的初始状态(会被哪些塔攻击到)
            for(int i=0;i<4;i++){
                int xx=dirx[i]+t.x;int yy=diry[i]+t.y;
                if(tvis[xx][yy]||xx<0||xx>=n||yy<0||yy>=m)
                    continue;
                que.push(Node(xx,yy,t.sum-1));
                tvis[xx][yy]=0;
            }
        }
    }
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    getchar();
    em.clear();
    for(int ppp=1;ppp<=T;ppp++){
        scanf("%d %d",&n,&m);
        getchar();
        memset(vis,0,sizeof(vis));
        for(int i=0;i<60;i++)
            for(int j=0;j<60;j++)
                maze[i][j].clear();
        char x;
        int ans=INF;enx=INF;eny=INF;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                scanf("%c",&x);
                if(x=='A'){
                    bfs(i,j,2,1);
                    vis[i][j]=1;
                }else if(x=='B'){
                    bfs(i,j,3,2);
                    vis[i][j]=1;
                }else if(x=='C'){
                    bfs(i,j,0,3);
                }else if(x=='D'){
                    bfs(i,j,2,4);
                    vis[i][j]=1;
                }else if(x=='E'){
                    bfs(i,j,1,5);
                    vis[i][j]=1;
                }else if(x=='$'){
                    stx=i;sty=j;
                }else if(x=='!'){
                    enx=i;eny=j;
                }else if(x=='#'){
                    vis[i][j]=1;
                }
            }
            getchar();
        }
        priority_queue <node> que;
        que.push(node(stx,sty,em,0));
        set <set<int> > event[60][60];//。。。。。。。。。。。。。。。。。。。。。。。。。。。。地图上每点的状态集初始为空
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                event[i][j].clear();
            }
        }
        event[stx][sty].insert(em);
        while(!que.empty()){
            node t=que.top();
            que.pop();
            if(t.x==enx&&t.y==eny){
                ans=t.ans;
                break;
            }else{
                for(int i=0;i<4;i++){
                    int xx=dirx[i]+t.x;int yy=diry[i]+t.y;
                    if(xx<0||yy<0||xx>=n||yy>=m||vis[xx][yy]) continue;
                    set <int> mix;
                    set_union(t.s.begin(),t.s.end(),maze[xx][yy].begin(),maze[xx][yy].end(),inserter(mix,mix.begin()));
                    if(event[xx][yy].find(mix)==event[xx][yy].end()){//。。。。。。。。。。。。。。。若新的状态在点上没有出现过,就入队
                        que.push(node(xx,yy,mix,0));
                        event[xx][yy].insert(mix);//。。。。。。。。。。。。。。。。。。。。。。。。更新点的状态集
                    }
                }
            }
        }
        if(ans==INF)
            ans=-1;
        printf("Case %d: %d\n",ppp,ans);
    }
}</span><span style="font-size:24px;">
</span>

Description

Three Kingdoms is a funny game. Often Liu Bei is weak and has to run away,so in the game Liu Bei has a skill called "Dunzou". This time you are playing the role of Liu Bei.As Cao Cao's power is so strong, there is nothing you can do but escaping. Please select an optimal path to achieve the purpose .
To simplify the problem, Liu Bei can only move in one of the four direction (up, down,right,left) each time. The map contains the following characters: 
‘A’ : Representative of watchtower, which has an attack range of 2(measured by Manhattan distance),and an attack damage of 1. 
‘B’ : Representative of Fort, which has an attack range of 3(measured by Manhattan distance),and an attack damage of 2. 
‘C’ : Representative of Flame, which has an attack damage of 3 to those who step onto it. 
‘D’ : Representative of Archer, which has anattack range of 2(measured by Manhattan distance), and an attack damage of 4. 
‘E’ : Representative of Ordinary soldier, which has anattack range of 1(measured by Manhattan distance), and an attack damage of 5. 
‘$’ : Representative of Liu Bei. 
‘!’ : Representative of Destination. 
'#' : Representative of obstacles 
‘.’ : Representative of floor. 
Liu Bei can not enter watchtower, forts, Archers, ordinary soldiers,But he can step onto flame or floor. 
Some important rules you should note: 
1.  Liu Bei will not be hurt by the same thing twice.For example,if Liu Bei has been hurt by one watchtower before,then he step into the attack range of some watchtower later,he will not be hurt. 
2.  When Liu Bei reach the destination,you should first judge the attack damage at the destination then finish the game. 
3.  You needn’t judge the attack damage at the start position. 
Please choose a path which LiuBei would cost the least HP. 

Input

In the first line there is an integer T, indicates the number of test cases.(T<=60) 
In each case,the first line of the input contains two integer n,m(1<=n,m<=50),reperesenting the size of map(n*m).Then follow n lines,each line contain m characters. 
There may be some blank lines between each case. 

Output

For each test case , output “Case d: “ where d is the case number counted from one.If Liu Bei can reach the destination then output the minimum HP LiuBei may lose, otherwise output -1.

Sample Input

1
4 3
.$.
ACB
ACB
.!.

Sample Output

Case 1: 6


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值