Problem 2021 : Princess in Danger

Princess in Danger

お姫様の危機
http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=2021

  • 問題概要

たくさんの街と道とその距離が与えられる。
お姫様が怪我したので首都から血を送らないといけない。
しかし、血は一定時間で溶けてつかえなくなるので、途中で冷凍しないといけない。
冷凍できる街の番号と血が最大冷凍できる時間があたえられる。
最短で血をとどけろ、届けられないならhelp!!

  • 解法

場所と血の残り時間を次元にした拡張ダイクストラ
priority_queueを使わないと間に合わない。

  • ソース
#include<iostream>
#include<algorithm>
#include<queue>

#define INF 1<<19

using namespace std;

class State{
public:
  int cost, blood, pos;
  bool operator < (const State s)const{
    if(cost != s.cost){
      return cost > s.cost;
    }
    return false;
  }
};

main(){
  
  int node, limit, freeze, road, start, goal;

  while( cin >> node >> limit >> freeze >> road >> start >> goal){
    if(node + limit  == 0)break;
    
    bool f[node];
    fill(f, f+node, false);
    for(int i=0; i<freeze; i++){
      int tmp;
      cin >> tmp;
      f[tmp] = true;
    }

    limit++;
    int edge[node][node];
    fill(&edge[0][0], &edge[node-1][node], INF);
    int cost[node][limit];
    fill(&cost[0][0], &cost[node-1][limit], INF);
    bool visited[node][limit];
    fill(&visited[0][0], &visited[node-1][limit], false);

    for(int i=0; i<road; i++){
      int f, to, c;
      cin >> f >> to >> c;
      edge[f][to] = edge[to][f] = c;
    }
    
    priority_queue<State> Q;
    State s;
    s.cost = 0;
    s.blood = limit-1;
    s.pos = start;
    cost[start][limit-1] = 0;
    
    Q.push(s);
    bool flag = false;
    int ans=0;
    while(!Q.empty()){
      State now = Q.top();
      Q.pop();

      int npos = now.pos;
      if(npos == goal){
	flag = true;
	ans = now.cost;
	break;
      }
      if(visited[npos][now.blood])continue;
      visited[npos][now.blood] = true;
      
      int nc = now.cost;
      int nb = now.blood;
      for(int i=0; i<node; i++){ 
	if(edge[npos][i] == INF)continue;
	for(int j=0; j+nb<limit; j++){
	  if(!f[npos] && j != 0)break;
	  int pc = nc + j + edge[npos][i];
	  int pb = nb + j - edge[npos][i];
	  if(pb < 0)continue;	  
	  if(visited[i][pb])continue;
	  if(cost[i][pb] > pc){
	    cost[i][pb] = pc;
	    s.pos = i;
	    s.blood = pb;
	    s.cost = pc;
	    Q.push(s);
	  }
	}
      }
    }

    if(flag)cout << ans << endl;
    else cout << "Help!" << endl;
  }
}

リベンジが果たせた。