ZOJ 3877 Earthstone Keeper(最短路)

本题如果去掉怪物选项就是双关键字最短路。

问题是现在多了一个怪物选项,因为这个怪物选项被杀死后他不会复生,因此我们不能重复计算这个值的答案。

所以对于每条过来的路,前面一个点遇到的怪物的后面的点就不用计算了,也就是去重。

根据这个思路,我们可以得到我们想要干的是当枚举到当前点,我们希望计算出他的cost然后减去前一个点由怪物造成的cost。

所以怪物这个点是特殊的点,普通点和普通点就是按规则连边,因为他们是相邻的,去重比较容易。

我们多考虑一种连边,因为题目告诉我们怪物是不可能相邻的,这个信息显然是有自己的道理,也给我们带来启发。

当我们枚举到怪物点的时,我们将他上下左右这四个点分别连单向边,时间为2,cost就是终点的cost-起点的cost

这样就成功跳过了怪物类的点

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e6+10;
const int mod=1e9+7;
int n,m;
char g[550][550];
int sx,sy,ex,ey;
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
vector<pll> num;
int h[N],ne[N],e[N],idx;
int cost[N],w[N];
int st[N];
int dis[N][2];
struct node{
    int x,y;
    int id;
    bool operator <(const node &t) const{
        if(x==t.x)
            return y>t.y;
        return x>t.x;
    }
};
void add(int a,int b,int c,int d){
    e[idx]=b,ne[idx]=h[a],cost[idx]=c,w[idx]=d,h[a]=idx++;
}
bool check(int x,int y){
    if(x>=0&&x<n&&y>=0&&y<m){
        if(g[x][y]!='#')
            return true;
    }
    return false;
}
int solve(int x,int y){
    int res=0;
    if(g[x][y]>='a'&&g[x][y]<='z')
        res+=(g[x][y]-'a'+1);
    int i;
    for(i=0;i<4;i++){
        int a=x+dx[i];
        int b=y+dy[i];
        if(!check(a,b))
            continue;
        if(g[a][b]>='A'&&g[a][b]<='Z')
            res+=(g[a][b]-'A'+1);
    }
    return res;
}
int get(int a,int b,int c,int d){
    int res=solve(c,d);
    int i,j;
    for(i=0;i<4;i++){
        int x=dx[i]+a;
        int y=dy[i]+b;
        if(check(x,y)){
            if(g[x][y]>='A'&&g[x][y]<='Z'){
                for(int k=0;k<4;k++){
                    int tmp1=dx[k]+x;
                    int tmp2=dy[k]+y;
                    if(check(tmp1,tmp2)){
                        if(tmp1==c&&tmp2==d){
                            res-=(g[x][y]-'A'+1);
                        }
                    }
                }
            }
        }
    }
    return res;
}
void dij(){
    int ans1,ans2;
    priority_queue<node> q;
    q.push({0,0,sx*m+sy});
    int i;
    for(i=0;i<=n*m;i++){
        st[i]=0;
        dis[i][1]=0x3f3f3f3f;
        dis[i][0]=0x3f3f3f3f;
    }
    dis[sx*m+sy][0]=dis[sx*m+sy][1]=0;
    while(q.size()){
        auto t=q.top();
        q.pop();
        if(st[t.id])
            continue;
        st[t.id]=1;
        if(t.id==ex*m+ey){
            ans1=t.x;
            ans2=t.y;
            break;
        }
        for(i=h[t.id];i!=-1;i=ne[i]){
            int j=e[i];
            if(dis[j][0]>dis[t.id][0]+cost[i]){
                dis[j][0]=dis[t.id][0]+cost[i];
                dis[j][1]=dis[t.id][1]+w[i];
                q.push({dis[j][0],dis[j][1],j});
            }
            else if(dis[j][0]==dis[t.id][0]+cost[i]&&dis[j][1]>dis[t.id][1]+w[i]){
                dis[j][1]=dis[t.id][1]+w[i];
                q.push({dis[j][0],dis[j][1],j});
            }
        }
    }
    printf("%d %d\n",ans1,ans2);
}
int main(){
    //ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        scanf("%d%d",&n,&m);
        int i,j;
        idx=0;
        for(i=0;i<=n*m;i++){
            h[i]=-1;
        }
        scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
        sx--,sy--,ex--,ey--;
        for(i=0;i<n;i++)
            scanf("%s",g[i]);
        for(i=0;i<n;i++){
            for(j=0;j<m;j++){
                int k;
                if(g[i][j]=='#')
                    continue;
                if(g[i][j]>='A'&&g[i][j]<='Z'){
                    num.clear();
                    for(k=0;k<4;k++){
                        int x=i+dx[k];
                        int y=j+dy[k];
                        if(check(x,y)){
                            num.push_back({x,y});
                        }
                    }
                    for(k=0;k<(int)num.size();k++){
                        for(int l=0;l<(int)num.size();l++){
                            if(k==l)
                                continue;
                            int tmp1=num[k].first*m+num[k].second;
                            int tmp2=num[l].first*m+num[l].second;
                            add(tmp1,tmp2,get(num[k].first,num[k].second,num[l].first,num[l].second),2);//计算到下个点的代价
                        }
                    }
                }
                else{
                    for(int k=0;k<4;k++){
                        int x=i+dx[k];
                        int y=j+dy[k];
                        if(!check(x,y))
                            continue;
                        if(g[x][y]>='A'&&g[x][y]<='Z')
                            continue;
                        add(i*m+j,x*m+y,solve(x,y),1);
                    }
                }
            }
        }
        dij();
    }
    return 0;
}
View Code

 

posted @ 2020-10-04 10:56  朝暮不思  阅读(163)  评论(0编辑  收藏  举报