两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路。
POJ3268-Silver Cow Party
//计算正逆最短路径之和的最大值
//Time:32Ms Memory:360K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX 1005
#define MAXE 100005
#define INF 0x3f3f3f3f
struct Edge {
int v, w, next;
Edge() {}
Edge(int vv, int ww, int nn):v(vv), w(ww), next(nn) {}
}e[2][MAXE];
int n, m, x;
int h[2][MAX], d[2][MAX];
bool v[MAX];
void spfa(int x, int r)
{
memset(v, false, sizeof(v));
queue<int> q;
q.push(x); d[r][x] = 0;
while (!q.empty()){
int cur = q.front();
q.pop(); v[cur] = false;
for (int i = h[r][cur]; i != -1; i = e[r][i].next)
{
int tv = e[r][i].v;
int tw = e[r][i].w;
if (d[r][tv] > d[r][cur] + tw) {
d[r][tv] = d[r][cur] + tw;
if (!v[tv]) {
q.push(tv); v[tv] = true;
}
}
}
}
}
int main()
{
memset(d, INF, sizeof(d));
memset(h, -1, sizeof(h));
scanf("%d%d%d", &n, &m, &x);
for (int i = 0; i < m; i++)
{
int a, b, t;
scanf("%d%d%d", &a, &b, &t);
if (a == b) {
m--; i--; continue;
}
e[0][i] = Edge(b, t, h[0][a]); //正向
e[1][i] = Edge(a, t, h[1][b]); //反向
h[0][a] = h[1][b] = i;
}
spfa(x, 0); //正向路径找返回最短路
spfa(x, 1); //反向路径找出发最短路
int Max = 0;
for (int i = 1; i <= n; i++)
Max = max(d[0][i] + d[1][i], Max);
printf("%d\n", Max);
return 0;
}
POJ3259-Wormholes
//SPFA或Bellman Ford算法
//判断是否有负权值回路
//Time:172Ms Memory:252K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 505
#define MAXN 5500
#define INF 0x3f3f3f3f
struct Edge {
int u, w, next;
Edge() {}
Edge(int uu, int ww, int nn) :u(uu), w(ww), next(nn) {}
}e[MAXN];
int n, m, w;
int le;
int h[MAX], d[MAX];
int cnt[MAX];
bool v[MAX];
bool spfa(int x)
{
memset(cnt, 0, sizeof(cnt));
memset(v, false, sizeof(v));
memset(d, INF, sizeof(d));
d[x] = 0;
queue<int> q;
q.push(x); cnt[x] = 1;
while (!q.empty()) {
int cur = q.front();
q.pop(); v[cur] = false;
for (int i = h[cur]; i != -1; i = e[i].next)
{
int u = e[i].u, w = e[i].w;
if (d[u] > d[cur] + w)
{
d[u] = d[cur] + w;
if (!v[u]) {
v[u] = true; q.push(u);
//如果某点入队列达到n次,则一定存在负权值回路
if (++cnt[u] == n) return true;
}
}
}
}
return false;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
le = 0;
memset(h, -1, sizeof(h));
scanf("%d%d%d", &n, &m, &w);
int a, b, t;
while (m--) {
scanf("%d%d%d", &a, &b, &t);
e[le] = Edge(b, t, h[a]); h[a] = le++;
e[le] = Edge(a, t, h[b]); h[b] = le++;
}
while (w--) {
scanf("%d%d%d", &a, &b, &t);
e[le] = Edge(b, -t, h[a]); h[a] = le++;
}
/*如果不是连通图则需要遍历所有点 //Time:1750Ms
int flag = false;
for (int i = 1; i <= n; i++)
if (spfa(i)) {
flag = true; break;
}
题目未说清是否为连通图
*/
if (spfa(1)) printf("YES\n");
else printf("NO\n");
}
return 0;
}