题目链接 https://www.luogu.com.cn/problem/UVA11374
题意:无向图中n个点给定起点s和终点e求最短路,不同的是有m条边是普通的,另外k条边中最多只能选1条。需要输出最短路的路径,长度,若用到了k条边中的某一条,则需要输出是在哪个点用到的, 否则输出"Ticket Not Used" 格式具体看题目。
思路:先在只有m条边的图中从起点和终点分别两次dijkstra, 求出到其他点的最短路分别为dis1[], dis[]。由于k条边中只能选1条,所以枚举其中的每一条边,这里假设选了u, v, 则最短路为dis1[u] + w(u, v) + dis[v],遍历求出最小值即可, 不要忘记和不使用k条边的最短路即dis1[e]比较。路径通过pre[]数组记录每个点的前驱来得到。
Note.多组数据,每组数据间需要有空行,且行末不能有多余空格。
// Decline is inevitable
// Romance will last forever
#include
using namespace std;
#define mst(a, x) memset(a, x, sizeof(a))
#define INF 0x3f3f3f3f
const int maxn = 5e2 + 10;
const int maxm = 4e3 + 10;
int n, e, m, k, head[maxn], cnt; //建图
bool vis[maxn];
int dis1[maxn], dis[maxn]; //dis1记录起点到每个点最短路 dis记录终点到每个点最短路
int pre1[maxn], pre[maxn]; //pre1记录起点跑最短路的每个点的前驱, pre则为终点
stack sta; //把pre1数组压入栈中 方便输出路径
struct Edge {
int to, dis, next;
}edge[maxm];
struct node {
int dis;
int pos;
node(int dis = 0, int pos = 0) : dis(dis), pos(pos) {}
bool operator < (const node &x)const {
return dis > x.dis;
}
};
void add_edge(int u, int v, int w) {
cnt++;
edge[cnt].to = v;
edge[cnt].dis = w;
edge[cnt].next = head[u];
head[u] = cnt;
}
priority_queue q;
void dijkstra(int s) { //dijkstra 求以s的起点的最短路
mst(pre, -1);
mst(vis, false);
mst(dis, 0x3f);
while(!q.empty()) q.pop();
dis[s] = 0;
q.push(node(0, s));
while(!q.empty()) {
node tmp = q.top();
q.pop();
int x = tmp.pos;
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x]; i; i = edge[i].next) {
int y = edge[i].to;
if(dis[y] > dis[x] + edge[i].dis)
dis[y] = dis[x] + edge[i].dis, pre[y] = x ;
if(!vis[y])
q.push(node(dis[y], y));
}
}
}
void solve() {
int s;
int t = 0;
while(scanf("%d%d%d", &n, &s, &e) !=EOF) {
if(t++) cout << "\n";
cnt = 0;
mst(head, 0);
mst(dis1, 0x3f);
mst(pre1, 0);
cin >> m;
for(int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
add_edge(u, v, w);
add_edge(v, u, w);
}
int ans = INF;
bool flag = true;
dijkstra(s);
for(int i = 1; i <= n; i++)
dis1[i] = dis[i], pre1[i] = pre[i];
dijkstra(e);
ans = dis1[e];
cin >> k;
int c = 0, d = 0;
for(int i = 0; i < k; i++) {
int u, v, w;
cin >> u >> v >> w;
if(dis1[u] + dis[v] + w < ans) {
c = u, d = v;
flag = false;
ans = dis1[u] + dis[v] + w;
}
if(dis1[v] + dis[u] + w < ans) {
flag = false;
c = v, d = u;
ans = dis1[v] + dis[u] + w;
}
}
if(flag) {
int x = s;
while(1) {
if(x == e) {
cout << x << "\n";
break;
}
cout << x << ' ';
x = pre[x];
}
cout << "Ticket Not Used\n";
cout << ans << "\n";
}
else {
int f = c;
sta.push(c);
while(pre1[c] != -1) {
sta.push(pre1[c]);
c = pre1[c];
}
while(!sta.empty())
cout << sta.top() << ' ', sta.pop();
while(1){
if(d == e) {
cout << d << "\n";
break;
}
cout << d << ' ';
d = pre[d];
}
cout << f << "\n";
cout << ans << "\n";
}
}
}
signed main() {
solve();
return 0;
}