1. 程式人生 > >SSLOJ 1319.埃雷薩拉斯尋寶

SSLOJ 1319.埃雷薩拉斯尋寶

queue using span 構圖 tput sin 復制 萬年 一定的

題目

題目描述

一萬兩千年前,當精靈還是在艾薩拉女王的統治下的時候,辛德拉就是是女王手下一名很有地位的法師了。他受任建造了一座城市,來保存女王的法師們進行魔法研究的成果和法術物品。這個城市就是埃雷薩拉斯。永恒之井爆炸以後,埃雷薩拉斯的精靈和艾薩拉聯系中斷,並失去了永恒之井的水做為能量的來源。辛德拉的後人為了對滿足魔法的欲望,他們捕獵了一個惡魔,伊莫塔爾。他們用水晶塔建造了一個帶有能量平衡系統的結界監獄,水晶塔從惡魔身上吸取能量,一部分維持結界監獄,一部分可以讓狂熱的精靈們吸收。這個系統萬年以來一直平安無事,可是現在,隨著惡魔的能量被消耗殆盡,已經難以維持結界監獄的消耗。統治者托爾塞林王子為了滿足自己的欲望,開始下令屠殺,除了少數狂熱者之外的其他人都要死,這樣才能減少對魔法能量的消耗。終於有一天,戈多克食人魔成功入侵了埃雷薩拉斯,並殺死了幾乎所有的精靈。他們把這裏當作自己王國的領地,名叫厄運之槌。面臨著滅頂之災的精靈們把他們祖先留下的寶藏用魔法結界藏了起來,以防戈多克食人魔搶走。

作為一名勇敢的探險者,你悄悄來到了埃雷薩拉斯尋找傳說中的寶藏。終於,你看見寶藏就在你的前方不遠處。但是你不能貿然前進,因為路上有著強大的魔法結界。這些結界根據能量的不同分為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");
}

SSLOJ 1319.埃雷薩拉斯尋寶