SSLOJ 1319.埃雷萨拉斯寻宝

题目

题目描述

一万两千年前,当精灵还是在艾萨拉女王的统治下的时候,辛德拉就是是女王手下一名很有地位的法师了。他受任建造了一座城市,来保存女王的法师们进行魔法研究的成果和法术物品。这个城市就是埃雷萨拉斯。永恒之井爆炸以后,埃雷萨拉斯的精灵和艾萨拉联系中断,并失去了永恒之井的水做为能量的来源。辛德拉的后人为了对满足魔法的欲望,他们捕猎了一个恶魔,伊莫塔尔。他们用水晶塔建造了一个带有能量平衡系统的结界监狱,水晶塔从恶魔身上吸取能量,一部分维持结界监狱,一部分可以让狂热的精灵们吸收。这个系统万年以来一直平安无事,可是现在,随着恶魔的能量被消耗殆尽,已经难以维持结界监狱的消耗。统治者托尔塞林王子为了满足自己的欲望,开始下令屠杀,除了少数狂热者之外的其他人都要死,这样才能减少对魔法能量的消耗。终于有一天,戈多克食人魔成功入侵了埃雷萨拉斯,并杀死了几乎所有的精灵。他们把这里当作自己王国的领地,名叫厄运之槌。面临着灭顶之灾的精灵们把他们祖先留下的宝藏用魔法结界藏了起来,以防戈多克食人魔抢走。
 
作为一名勇敢的探险者,你悄悄来到了埃雷萨拉斯寻找传说中的宝藏。终于,你看见宝藏就在你的前方不远处。但是你不能贸然前进,因为路上有着强大的魔法结界。这些结界根据能量的不同分为P种,踏入每种结界,你都会受到一定的伤害。为了拿到宝藏,这些伤害算不了什么。但是你要尽可能地减少伤害,请你设计一条路线,使你穿越结界获取宝藏受到的伤害最少。下面是一个魔法结界能量示意图,结界是一个正方形,内部有P种不同的能量,每种字母表示一种能量。你从最上端开始走,每次可以走到与你所在的位置上下左右相邻的临位,或者在同种能量结界中任意传送。重复进入同一种能量结界不会再次受到伤害。
 
|AAABBC|
|ABCCCC|
|AABBDD|
|EEEEEF|
|EGGEFF|
|GGFFFF|
 
你有H点生命值,请你在贸然行动之前先判断是否能够活着(生命值大于0)穿越结界拿到宝藏,如果能够,请求出最多剩余的生命值。
 

输入

第1行 三个非负整数 N,P,H。N为结界的边长,P为不同的能量结界的数量,H为你的生命值。
第2-P+1行 每行一个非负整数,表示走到该种能量结界受到的伤害值。
第P+2至第P+2+N行 每行N个正整数,为地图上该单元格的能量种类的编号,编号为1..P。

输出

如果你能够穿越结界到达对岸的宝藏,输出最多剩余的生命值。如果不能穿越,输出NO。

输入样例复制

6 7 10
3
1
2
2
1
1
3
1 1 1 2 2 3
1 2 3 3 3 3
1 1 2 2 4 4
5 5 5 5 5 6
5 7 7 5 6 6
7 7 6 6 6 6

输出样例复制

7

说明

样例说明
路线为
起始-2-5-6-目标
1 1 1 2 2 3
1 2 3 3 3 3
1 1 2 2 4 4
5 5 5 5 5 6
5 7 7 5 6 6
7 7 6 6 6 6

数据规模
对于40%数据
4<=N<=10

对于100%数据
4<=N<=50
1<=P<=N*N
0<=H<=200000000

分析

  • 不难想到,我们直接构图跑最短路
  • 但是构图是关键
  • 因为在同种结界中是无需消耗的的
  • 所以我们可以直接定义p个点,直接连边跑最短路
  • 连一个超级源点,一个超级汇点

 

代码

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int N=110;
const int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
struct node{
    int to,next,w;
}a[N*N*4];
int n,p,h,tot,ans;
int ls[N*N],f[N*N],power[N][N],w[N*N];
bool v[N*N];
queue<int> q;
void add(int x,int y,int w)
{
    a[++tot].next=ls[x];
    a[tot].to=y;
    a[tot].w=w;
    ls[x]=tot;
}
void spfa()
{
    memset(f,0x3f,sizeof(f)); 
    q.push(0);v[0]=1;f[0]=0;
    while(!q.empty()){
        int x=q.front();q.pop();v[x]=0;
        for(int i=ls[x];i;i=a[i].next){
            int y=a[i].to;
            if(f[x]+a[i].w<f[y]){
                f[y]=f[x]+a[i].w;
                if(!v[y]){
                    v[y]=1;
                    q.push(y);
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&p,&h);
    for(int i=1;i<=p;i++)
        scanf("%d",&w[i]);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        scanf("%d",&power[i][j]);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++){
          for(int k=0;k<4;k++)
          {
              int x=i+dx[k],y=j+dy[k];
              if(!power[x][y]||power[i][j]==power[x][y]) continue;
              add(power[i][j],power[x][y],w[power[x][y]]);
          }
      }
    for(int i=1;i<=n;i++)
        add(0,power[1][i],w[power[1][i]]);
    spfa();
    for(int i=1;i<=n;i++)
        ans=max(ans,h-f[power[n][i]]); 
    if(ans>0) printf("%d",ans);
    else printf("NO");
}

 

posted @ 2019-04-27 15:24  Melted_czj  阅读(232)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色