UVA—Funny Car Racing Dijkstra + 堆優化

題目傳送門

在這裏插入圖片描述

題意:

有一個賽車跑道,可以看做一個加權有向圖。每個跑道(有向邊)還有一個特點就是,會週期性地打開a秒,然後關閉b秒。只有在賽車進入一直到出來,該跑道一直處於打開狀態,賽車才能通過。

開始時所有跑道處於剛打開的狀態,求從起點到終點的最短時間。

分析:

和普通的單源最短路類似,在更新邊的權值的時候,更改下條件即可。

首先需要判斷時間time,time = dis[pos] % ( 開啓時間 + 關閉時間 ) (去除完整週期)。那麼很容易得到 : 當 time > open 的時候爲關閉狀態。

對於關閉狀態:
權值爲:剩餘關閉時間 + val

對於開啓狀態:
1、如果剩餘開啓時間足夠通過,權值爲:val(注意存在恰好通過)
2、剩餘時間不足以通過,權值爲:剩餘總共時間 + val

AC代碼:

#include <iostream>
#include <vector>
#include <utility>
#include <cstring>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <cstdio>
#include <set>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;


#define MAXN 1000000
#define INT_MAX 0x3ffffff
typedef pair<int, int> P;
struct Edge
{
	int first;
	int open;
	int close;
	int second;
	bool operator < (const Edge& t)const {
		return t.second < this->second;
	}
};

vector<Edge>vec[MAXN];
priority_queue<Edge, vector<Edge> >que;
ll dis[MAXN];
bool vis[MAXN];
ll N, M, START, END;

void Dijkstra(int start) {

	dis[start] = 0;
	que.push({ start,0,0,0 });
	while (!que.empty()) {
		Edge tmp = que.top();
		que.pop();
		if (vis[tmp.first] == true) {
			continue;
		}
		vis[tmp.first] = true;
		for (int i = 0; i < vec[tmp.first].size(); i++) {
			ll pos = vec[tmp.first][i].first;
			ll val = vec[tmp.first][i].second;
			ll open = vec[tmp.first][i].open;
			ll close = vec[tmp.first][i].close;
			ll time = dis[tmp.first] % (open + close);
			if (time >= open) {
				dis[pos] = min(dis[tmp.first] + (close - (time - open)) + val, dis[pos]);
				if (!vis[pos])
					que.push({ pos,open,close,dis[pos] });
			}
			else {
				if (open - time >= val) {	
					dis[pos] = min(dis[tmp.first] + val, dis[pos]);
					if (!vis[pos])
						que.push({ pos,open,close,dis[pos] });
				}
				else {
					dis[pos] = min(dis[tmp.first] + val + (open + close) - time, dis[pos]);
					if (!vis[pos])
						que.push({ pos,open,close,dis[pos] });
				}

			}
		}
	}
}

int main() {
	ios;
	ll T = 0;
	while (cin>> N >> M >> START >> END) {
		fill(dis, dis + N + 1, INT_MAX);
		memset(vis, false, sizeof(vis));
		for (vector<Edge>& t : vec) {
			t.clear();
		}
		for (int i = 0; i < M; i++) {
			ll a, b, c, d, e;
			cin >> a >> b >> c >> d >> e;
			if (c < e)	
				continue;
			vec[a].push_back({ b,c,d,e });
		}
		Dijkstra(START);
		cout << "Case " << ++T << ": ";
		cout << dis[::END] << endl;

	}




	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章