poj3169

差分约束系统

差分约束系统有两种方式可以求解,最短路和最长路。当我们把不等式整理成d[a]+w<=d[b]时,我们求最长路。整理成d[a]+w>=d[b]时,我们求最短路。当求最短路时,我们通常要把各点距离初始化为正无穷,求最短路,把各点距离逐渐减小,直到符合所有不等式。也就是开始各点不符合条件,后来通过减小变得符合了,所以一定是符合条件的最大值。既然是求最大值,并且是减小各点距离,也就是把各点由数轴的右侧向左侧拉,所以我们一定要选择一个最终在数轴最左侧的点,并初始化为0,把所有正无穷的点拉近到符合不等式。最长路同理。

另外本题我的做法判断impossible的情况是不完全的,暂未发现谁处理得比较正确。我的代码只能判断起点可达的点是否有负环。

View Code
#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;
}

你可能感兴趣的:(poj)