読者です 読者をやめる 読者になる 読者になる

Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

IOI 2011-day2 Crocodile's Underground City

問題文 : ワニの地下都市(pdf注意)

解法 :
出口につけばすぐに出ることが出来るので, 出口のノードのコストは0にしておく.

そうでないすべてのノードについて, "出口までたどり着ける最短時間" "出口までたどり着ける2 番目の最短時間"を状態としてdijkstra を行う. ただし, 2 番目の最短時間の昇順で優先にノードを取っていく.

前計算にO(N log N), dijkstra にO(M log N) で, 計O((M + N) log N) 時間でこの問題が解ける.

コード :

#include <cstring>
#include <algorithm>
#include <climits>
#include <vector>
#include <queue>

#define MAX_N (100000)
#define MAX_M (1000000)
#define INF (1ll << 34)

using namespace std;

typedef long long lint;

struct edge {
	int to;
	lint fcost, ncost;
	edge(int to, lint fcost = INF, lint ncost = INF) : to(to), fcost(fcost) {}
	edge(){}
};

bool operator < (const edge &a, const edge &b)
{
	return (a.ncost < b.ncost);
}

bool operator > (const edge &a, const edge &b)
{
	return (b < a);
}

vector<edge> G[MAX_N];
edge g[MAX_N];
lint cost[MAX_N];

int travel_plan(int N, int M, int R[][2], int L[], int K, int P[])
{
	for (int i = 0; i < M; i++){
		G[R[i][0]].push_back(edge(R[i][1], L[i]));
		G[R[i][1]].push_back(edge(R[i][0], L[i]));
	}
	
	for (int i = 0; i < N; i++) cost[i] = INF;
	
	for (int i = 0; i < K; i++){
		cost[P[i]] = 0;
	}
	
	
	priority_queue<edge, vector<edge>, greater<edge> > pq;
	
	for (int i = 0; i < N; i++){
		if (cost[i]){
			g[i].to = i;
			g[i].fcost = g[i].ncost = INF;
			for (int j = 0; j < G[i].size(); j++){
				lint newcost = G[i][j].fcost + cost[G[i][j].to];
				if (newcost > g[i].ncost) continue;
				else if (newcost > g[i].fcost){
					g[i].ncost = newcost;
				}
				else {
					g[i].ncost = g[i].fcost;
					g[i].fcost = newcost;
				}
			}
			pq.push(g[i]);
		}
	}
	
	for (; pq.size(); pq.pop()){
		edge x = pq.top();
		
		if (cost[x.to] <= x.ncost) continue;
		
		cost[x.to] = x.ncost;
		
		for (int i = 0; i < G[x.to].size(); i++){
			int npos = G[x.to][i].to;
			lint newcost = G[x.to][i].fcost + cost[x.to];
			if (newcost > g[npos].ncost) continue;
			else if (newcost > g[npos].fcost){
				g[npos].ncost = newcost;
			}
			else {
				g[npos].ncost = g[npos].fcost;
				g[npos].fcost = newcost;
			}
			pq.push(g[npos]);
		}
	}
	
	return (cost[0]);
}