题意:
有n个城镇,他们两两之间都有双向公路连接。其中有m条是高速公路,其它都是普通公路。
每条高速公路的时间代价为a,普通公路时间代价为b。
现在给你m条高速公路的情况,让你求出1到n的最少时间代价。
思路:
最短路。我就怎么感觉这么像之前做的一道题。
先根据高速公路分别求出城镇1和城镇n到其它各点的最短距离(有的城镇是高速公路不可达的,设为无穷大)。
现在把普通公路也融入进去。例如从1出发的,枚举每个城镇x,如果城镇1和城镇x没有高速公路相连并且b小于当前的最短距离,即可将此最短距离更新为b。(需要注意的是,此时的所得的最短距离并不一定是1到x的最短距离。)
然后再枚举每个城镇作为1到n的中继点,取最小值即可。
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
const int INF = 0x3f3f3f3f;
typedef long long LL;
struct Edge {
int v, next;
}edge[10*N];
int head[N], ec;
void addEdge(int u, int v) {
edge[ec] = (Edge){v, head[u]};
head[u] = ec++;
}
int n, m, a, b;
LL d1[N], d2[N];
bool vis[N];
struct PP {
int u;
LL dis;
bool operator < (const PP &cmp) const {
return dis > cmp.dis;
}
};
priority_queue <PP> pq;
void Dijkstra(int s, LL *d, bool *vis) {
pq.push((PP){s, 0});
d[s] = 0;
while(!pq.empty()) {
int u = pq.top().u;
pq.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = head[u];i != -1; i = edge[i].next) {
Edge &e = edge[i];
if(d[u]+a < d[e.v]) {
d[e.v] = d[u]+a;
pq.push((PP){e.v, d[e.v]});
}
}
}
}
bool c1[N], c2[N];
void solve() {
memset(d1, INF, sizeof(d1));
memset(vis, false, sizeof(vis));
Dijkstra(1, d1, vis);
for(int i = 1;i <= n; i++) if(!c1[i] && d1[i] > b) d1[i] = b;
memset(d2, INF, sizeof(d2));
memset(vis, false, sizeof(vis));
Dijkstra(n, d2, vis);
for(int i = 1;i <= n; i++) if(!c2[i] && d2[i] > b) d2[i] = b;
LL res = d1[n], tmp = 0x3f3f3f3f3f3f3f3f;
for(int i = 1;i <= n; i++)
res = min(res, d1[i]+d2[i]);
printf("%lld\n", res);
}
int main() {
while(scanf("%d%d%d%d", &n, &m, &a, &b) != EOF) {
memset(head, -1, sizeof(head)), ec = 0;
memset(c1, false ,sizeof(c1));
memset(c2, false ,sizeof(c2));
int u, v;
c1[1] = true, c2[n] = true;
for(int i = 0;i < m; i++) {
scanf("%d%d", &u, &v);
if(u == 1) c1[v] = true;
if(v == 1) c1[u] = true;
if(u == n) c2[v] = true;
if(v == n) c2[u] = true;
addEdge(u, v);
addEdge(v, u);
}
solve();
}
return 0;
}