差分约束系统 POJ 3169 Layout

题目传送门

题意:有两种关系,n牛按照序号排列,A1到B1的距离不超过C1, A2到B2的距离不小于C2,问1到n的距离最大是多少.如果无限的话是-2, 如果无解是-1

分析:第一种可以写这样的方程:d[v] - d[u] <= w1, u到v连一条权值为w1的边,第二种这样:d[v] - d[u] >= w2 => d[u] - d[v] <= -w2,v到u连一条-w2的边.当然根据题目还有i+1 到 i连权值0的边.最短路就是为了d[v] <= d[u] + w[u][v], 也就是d[v] - d[u] <= ans.求出最短路也就是满足了所有方程的约束条件.如果INF无解,如果负环无数解,否则就是ans了.

//#include <bits/stdc++.h>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int N = 1e3 + 5;
const int E = 2e4 + 5;
const int INF = 0x3f3f3f3f;
struct Edge	{
	int v, w, nex;
	Edge()	{}
	Edge(int v, int w, int nex) : v (v), w (w), nex (nex) {}
}edge[E*2];
int head[N];
int d[N];
bool vis[N];
int cnt[N];
int n, m1, m2, e;

void init(void)	{
	memset (head, -1, sizeof (head));
	e = 0;
}

void add_edge(int u, int v, int w)	{
	edge[e] = Edge (v, w, head[u]);
	head[u] = e++;
}

bool SPFA(int s)	{
	memset (vis, false, sizeof (vis));
	memset (cnt, 0, sizeof (cnt));
	memset (d, INF, sizeof (d));
	d[s] = 0;	cnt[s] = 0;	vis[s] = true;
	queue<int> que;	que.push (s);
	while (!que.empty ())	{
		int u = que.front ();	que.pop ();
		vis[u] = false;
		for (int i=head[u]; ~i; i=edge[i].nex)	{
			int v = edge[i].v, w = edge[i].w;
			if (d[v] > d[u] + w)	{
				d[v] = d[u] + w;
				if (!vis[v])	{
					vis[v] = false;	que.push (v);
					if (++cnt[v] > n)	return true;
				}
			}
		}
	}
	return false;
}

int main(void)	{
	while (scanf ("%d%d%d", &n, &m1, &m2) == 3)	{
		init ();
		for (int i=1; i<n; ++i)	{
			add_edge (i+1, i, 0);
		}
		for (int u, v, w, i=1; i<=m1; ++i)	{
			scanf ("%d%d%d", &u, &v, &w);
			add_edge (u, v, w);
		}
		for (int u, v, w, i=1; i<=m2; ++i)	{
			scanf ("%d%d%d", &u, &v, &w);
			add_edge (v, u, -w);
		}
		if (SPFA (1))	puts ("-1");
		else	{
			bool ok = true;
			for (int i=1; i<=n; ++i)	{
				if (d[i] == INF)	{
					ok = false;	break;
				}
			}
			if (!ok)	puts ("-2");
			else	printf ("%d
", d[n]);
		}
	}	

	return 0;
}

  

编译人生,运行世界!
原文地址:https://www.cnblogs.com/Running-Time/p/5010256.html