题目:
http://poj.org/problem?id=4046
题意:
n个点,m条边。点和边分别有相应的权值。
Q个询问,给出起点终点,一条路径中选择权值最大的点加入花费的情况下,输出最小花费。
思路:
枚举每个点作为最大权值点,跑一次spfa,如果经过询问的端点则更新询问的答案。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const ll INF = 1e16;
const int maxn = 1005;
const int maxm = 2e4+5;
int val[maxn], n, m, Q;
int a[maxm], b[maxm];
ll ans[maxm];
struct Edge {
int to, w, next;
}edge[maxm*2];
int head[maxn], tot;
void addedge(int u, int v, int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].to = u;
edge[tot].w = w;
edge[tot].next = head[v];
head[v] = tot++;
}
ll dis[maxn];
bool vis[maxn];
void spfa(int s)
{
for(int i = 0; i <= n; ++i) {
dis[i] = INF;
vis[i] = 0;
}
queue<int> que;
que.push(s);
vis[s] = 1;
dis[s] = 0;
while(!que.empty()) {
int u = que.front(); que.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(dis[v] > dis[u] + w && val[s] >= val[v]) {
dis[v] = dis[u] + w;
if(!vis[v]) {
vis[v] = 1;
que.push(v);
}
}
}
}
for(int i = 1; i <= Q; ++i) {
int u = a[i], v = b[i];
if(dis[u] != INF && dis[v] != INF && ans[i] > dis[v]+dis[u]+val[s]) {
ans[i] = dis[u] + dis[v] + val[s];
//printf("(%d, %d)%d\n", u, v, ans[i]);
}
}
}
void init()
{
memset(head, -1, sizeof(head));
tot = 0;
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d %d", &n, &m)) {
if(n == 0 && m == 0) break;
init();
for(int i = 1; i <= n; ++i) {
scanf("%d", &val[i]);
}
int u, v, w;
for(int i = 0; i < m; ++i) {
scanf("%d %d %d", &u, &v, &w);
addedge(u, v, w);
}
scanf("%d", &Q);
for(int i = 1; i <= Q; ++i) {
scanf("%d %d", &a[i], &b[i]);
ans[i] = INF;
}
for(int i = 1; i <= n; ++i) spfa(i);
for(int i = 1; i <= Q; ++i) {
if(ans[i] == INF) {
printf("-1\n");
}
else printf("%I64d\n", ans[i]);
}
printf("\n");
}
return 0;
}