1. 程式人生 > >#106-[差分約束]關係運算圖

#106-[差分約束]關係運算圖

Description

給出一有向圖,圖中每條邊都被標上了關係運算符‘<’,‘>’,‘=’。現在要給圖中每個頂點標上一個大於等於0,小於等於k的某個整數使所有邊上的符號得到滿足。若存在這樣的k,則求最小的k,若任何k都無法滿足則輸出NO。

例如下表中最小的k為2。

結點1>結點2

結點2>結點3

結點2>結點4

結點3=結點4

如果存在這樣的k,輸出最小的k值;否則輸出‘NO’。

Input

共二行,第一行有二個空格隔開的整數n和m。n表示G的結點個數,m表示G的邊數,其中1<=n<=1000, 0<=m<=10000。全部結點用1到n標出,圖中任何二點之間最多隻有一條邊,且不存在自環。

第二行共有3m個用空格隔開的整數,第3i-2和第3i-1(1<=i<=m)個數表示第i條邊的頂點。第3i個數表示第i條邊上的符號,其值用集合{-1,0,1}中的數表示:-1表示‘<’, 0 表示‘=’, 1表示‘>’。

Output

僅一行,如無解則輸出‘NO’;否則輸出最小的k的值。

Sample Input

4 4
1 2 -1 2 3 0 2 4 -1 3 4 -1

Sample Output

2

差分約束比較模板的一道題,求最小值用SPFA最長路.

#include <iostream>
#include <cstring>
#include <queue>

#define SIZE 1010
#define INF 1e+09

using namespace std;

struct edge // 定義一條邊的結構體.
{
	int to, dis;
};

vector<edge> graph[SIZE];
queue<int> q;
int dis[SIZE], count[SIZE], n;
bool inqueue[SIZE];

void spfa(void) // SPFA最長路
{
	int u, v, w, i, res = 0;
	
	for (i = 1; i <= n + 1; ++i)
	{
		dis[i] = -INF;
	}
	q.push(0);
	inqueue[0] = true;
	++count[0];
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		inqueue[u] = false;
		for (i = 0; i < graph[u].size(); ++i)
		{
			v = graph[u][i].to;
			w = graph[u][i].dis;
			if (dis[v] < dis[u] + w) // 這裡條件換一下就可以了
			{
				dis[v] = dis[u] + w;
				if (!inqueue[v])
				{
					if (++count[v] >= n) // 存在正環
					{
						printf("NO");
						return;
					}
					q.push(v);
					inqueue[v] = true;
				}
			}
		}
	}
	
	printf("%d", dis[n+1]);
	
	return;
}

int main(int argc, char** argv)
{
	int m, u, v, w, i;
	
	scanf("%d%d", &n, &m);
	while (m--)
	{
		scanf("%d%d%d", &u, &v, &w);
		switch (w) // 建圖!
		{
			case -1:
				graph[u].push_back({v, 1});
				break;
			case 0:
				graph[u].push_back({v, 0});
				graph[v].push_back({u, 0});
				break;
			case 1:
				graph[v].push_back({u, 1});
				break;
		}
	}
	
	for (i = 1; i <= n; ++i)
	{
		graph[0].push_back({i, 0});
		graph[i].push_back({n + 1, 0});
	}
	spfa();
	
	return 0;
}