POJ 3268 Silver Cow Party (dijkstra)
题意:给出一个单向带权图和一个点s,求点u,u到s的最短路径和s到u的最短路径之和最大。
思路:
对于s到任意点的最短路,直接dijkstra可以求出。
对于任意点到s的最短路,将所有边反向然后求一次最短路。容易证明,求出的s到任意点v的最短路s-->v就是原来没有反向的图的v-->s的最短路。
所以先求一次dijkstra,保存此次的结果,然后把所有的边反向,权值不变,再求一次dijkstra,将两次结果加起来,计算它们之中的最大值。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 1010 #define inf 0x3f3f3f3f using namespace std; int n, m; int value[maxn][maxn]; int dis[maxn]; bool vis[maxn]; int dis2[maxn]; void dijkstra(int s) { memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) dis[i] = inf; dis[s] = 0; while(true) { int v = -1; for (int j = 1; j <= n; j++) { if (!vis[j] && (v == -1 || dis[j]< dis[v])) v = j; } if (v == -1) break; vis[v] = true; for (int j = 1; j <= n; j++) { if (dis[j] > dis[v] + value[v][j]) { dis[j] = dis[v] + value[v][j]; } } } } void dijkstra2(int s) { memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) dis2[i] = inf; dis2[s] = 0; while (true) { int v = -1; for (int j = 1; j <= n; j++) { if (!vis[j] && (v == -1 || dis2[j]< dis2[v])) v = j; } if (v == -1) break; vis[v] = true; for (int j = 1; j <= n; j++) { if (dis2[j] > dis2[v] + value[j][v]) { dis2[j] = dis2[v] + value[j][v]; } } } } int main() { int aim; while (scanf("%d %d %d", &n, &m, &aim) != EOF) { for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) value[i][j] = inf; while (m--) { int u, v, w; cin >> u >> v >> w; if (w < value[u][v]) value[u][v] = w; } dijkstra(aim); dijkstra2(aim); int ans = 0; for (int i = 1; i <= n; i++) if (dis[i] != inf && dis2[i] != inf) ans = max(ans, dis[i] + dis2[i]); printf("%d\n", ans); } return 0; }
注:这里的dijkstra用的是一般方法,复杂度(V^2),也可以用最小堆(优先队列)处理,复杂度(E log(V))