poj3169
差分约束系统
差分约束系统有两种方式可以求解,最短路和最长路。当我们把不等式整理成d[a]+w<=d[b]时,我们求最长路。整理成d[a]+w>=d[b]时,我们求最短路。当求最短路时,我们通常要把各点距离初始化为正无穷,求最短路,把各点距离逐渐减小,直到符合所有不等式。也就是开始各点不符合条件,后来通过减小变得符合了,所以一定是符合条件的最大值。既然是求最大值,并且是减小各点距离,也就是把各点由数轴的右侧向左侧拉,所以我们一定要选择一个最终在数轴最左侧的点,并初始化为0,把所有正无穷的点拉近到符合不等式。最长路同理。
另外本题我的做法判断impossible的情况是不完全的,暂未发现谁处理得比较正确。我的代码只能判断起点可达的点是否有负环。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define V 1005
#define E 20001
int pnt[E], cost[E], nxt[E];
int e, head[V], dist[V];
bool vis[V];
int cnt[V];
int relax(int u, int v, int c)
{
if (dist[v] > dist[u] + c)
{
dist[v] = dist[u] + c;
return 1;
}
return 0;
}
inline void addedge(int u, int v, int c)
{
pnt[e] = v;
cost[e] = c;
nxt[e] = head[u];
head[u] = e++;
}
int SPFA(int src, int n)
{
int i;
memset(cnt, 0, sizeof(cnt));
memset(vis, false, sizeof(vis));
for (i = 1; i <= n; ++i)
dist[i] = INF;
dist[src] = 0;
queue<int> Q;
Q.push(src);
vis[src] = true;
++cnt[src];
while (!Q.empty())
{
int u, v;
u = Q.front();
Q.pop();
vis[u] = false;
for (i = head[u]; i != -1; i = nxt[i])
{
v = pnt[i];
if (1 == relax(u, v, cost[i]) && !vis[v])
{
Q.push(v);
vis[v] = true;
if ((++cnt[v]) > n)
return -1;
}
}
}
if (dist[n] == INF)
return -2;
return dist[n];
}
int main()
{
//freopen("t.txt", "r", stdin);
int n, ml, md;
int i, a, b, c;
e = 0;
scanf("%d%d%d", &n, &ml, &md);
memset(head, -1, sizeof(head));
for (i = 0; i < ml; ++i)
{
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
}
for (i = 0; i < md; ++i)
{
scanf("%d%d%d", &a, &b, &c);
addedge(b, a, -c);
}
printf("%d\n", SPFA(1, n));
return 0;
}