原題:
https://cses.fi/problemset/task/1671
題意:
給定一張有向圖(n 點、m 邊),邊權非負。從節點 1 出發,輸出到每個節點的最短距離。若不可達,距離會維持為很大的數(常設為 INF)並輸出。
解題思路:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
const long long INF = (long long)4e18;
vector<vector<pair<int,int>>> g(n+1);
for(int i=0;i<m;i++){
int a,b,w; cin>>a>>b>>w;
g[a].push_back({b,w});
}
vector<long long> dist(n+1, INF);
priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;
dist[1]=0; pq.push({0,1});
while(!pq.empty()){
auto [d,u]=pq.top(); pq.pop();
if(d!=dist[u]) continue; // 已有更短解
for(auto [v,w]: g[u]){
if(dist[v] > d + w){
dist[v] = d + w;
pq.push({dist[v], v});
}
}
}
for(int i=1;i<=n;i++){
cout << dist[i] << (i==n?'\n':' ');
}
return 0;
}
原題:
https://cses.fi/problemset/task/1195
題意:
從節點 1 走到節點 n,你可以對 其中一條邊 使用折扣(價格 / 2,向下取整)。求最短距離。
解題思路:
#include <bits/stdc++.h>
using namespace std;
struct State{
long long d; int u; int used; // used=0/1
bool operator<(State const& o) const { return d > o.d; }
};
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
int n, m; if(!(cin>>n>>m)) return 0;
vector<vector<pair<int,int>>> g(n+1);
for(int i=0;i<m;i++){
int a,b,w; cin>>a>>b>>w;
g[a].push_back({b,w});
}
const long long INF = (long long)4e18;
vector<long long> d0(n+1, INF), d1(n+1, INF);
priority_queue<State> pq;
d0[1]=0; pq.push({0,1,0});
while(!pq.empty()){
auto [d,u,used]=pq.top(); pq.pop();
if(used==0 && d!=d0[u]) continue;
if(used==1 && d!=d1[u]) continue;
for(auto [v,w]: g[u]){
// 不用折扣
if(used==0 && d0[v] > d + w){
d0[v] = d + w;
pq.push({d0[v], v, 0});
}
if(used==1 && d1[v] > d + w){
d1[v] = d + w;
pq.push({d1[v], v, 1});
}
// 這條邊使用折扣
if(used==0){
long long nd = d + (long long)w/2; // 向下取整
if(d1[v] > nd){
d1[v] = nd;
pq.push({d1[v], v, 1});
}
}
}
}
cout << d1[n] << "\n"; // 必須使用過一次折扣的最短距離
return 0;
}
原題:
https://leetcode.com/problems/network-delay-time/description/
題意:
給定有向邊 times[i] = {u, v, w} 表示 u→v 需要時間 w,總共有 n 個節點,從起點 k 發送訊號。訊號到達所有節點需要的最久時間是多少?若有節點不可達回傳 -1。
解題思路:
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
const long long INF = (long long)4e18;
vector<vector<pair<int,int>>> g(n+1);
for(auto &e: times) g[e[0]].push_back({e[1], e[2]});
vector<long long> dist(n+1, INF);
priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;
dist[k]=0; pq.push({0,k});
while(!pq.empty()){
auto [d,u]=pq.top(); pq.pop();
if(d!=dist[u]) continue;
for(auto [v,w]: g[u]){
if(dist[v] > d + w){
dist[v] = d + w;
pq.push({dist[v], v});
}
}
}
long long ans = 0;
for(int i=1;i<=n;i++) ans = max(ans, dist[i]);
return ans >= INF/2 ? -1 : (int)ans;
}
};
原題:
https://leetcode.com/problems/path-with-minimum-effort/
題意:
給定高度矩陣 h,從 (0,0) 走到 (n-1,m-1)。一步的費用為相鄰格高度差的絕對值。路徑的成本定義為沿途所有步驟費用的最大值。求使該「最大值」最小的路徑成本。
解題思路:
class Solution {
public:
int minimumEffortPath(vector<vector<int>>& h) {
int n = h.size(), m = h[0].size();
const int INF = 1e9;
vector<vector<int>> dist(n, vector<int>(m, INF));
using T = tuple<int,int,int>; // d,x,y
priority_queue<T, vector<T>, greater<T>> pq;
auto inside = [&](int x,int y){return x>=0&&x<n&&y>=0&&y<m;};
int dx[4]={1,-1,0,0}, dy[4]={0,0,1,-1};
dist[0][0]=0; pq.push({0,0,0});
while(!pq.empty()){
auto [d,x,y]=pq.top(); pq.pop();
if(d!=dist[x][y]) continue;
if(x==n-1 && y==m-1) return d; // 最早彈出即最優
for(int k=0;k<4;k++){
int nx=x+dx[k], ny=y+dy[k];
if(!inside(nx,ny)) continue;
int w = abs(h[nx][ny]-h[x][y]);
int nd = max(d, w);
if(dist[nx][ny] > nd){
dist[nx][ny] = nd;
pq.push({nd, nx, ny});
}
}
}
return dist[n-1][m-1];
}
};