图论(差分约束)--

1.如果求未知数的最大值,那么按小于等于建图后求最短路即可。

2.如果求未知数的最小值,那么按大于等于建图后求最长路即可。

3.注意所有数据的关系,不能漏掉关系,还有与附加源点的关系。

①:对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值 
②:对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值 
③:存在负环的话是无解 
④:求不出最短路(dist[ ]没有得到更新)的话是任意解 

例题:

Description

蒜头君苦练厨艺,终于成为了某高档酒店的大厨。

每天上班,蒜头君会被要求做 n 份菜。既然是高档酒店,那么客人们当然是很讲究的,尤其对于上菜的时间有很多要求。客人们的要求被分成下列四种:

菜品 a 的上菜时间必须比菜品 b 的上菜时间早 d 分钟或者更早。

菜品 a 的上菜时间必须比菜品 b 的上菜时间迟 d 分钟或者更迟。

菜品 a 的上菜时间在 d 分钟以后(包含 d 分钟)。

菜品 a 的上菜时间在 d 分钟之前(包含 d 分钟)。

蒜头君的上班时间记为 0 分钟。为了节约时间,在满足客人们要求的情况下,蒜头君希望最后上的一道菜的时间尽可能的早。(每道菜的上菜时间必须不早于蒜头君的上班时间)


Input
第一行输入一个整数 n,表示一共需要上 n 道菜。

第二行输入一个整数 m,表示客人们的要求数量。

接下里 m 行,每行先输入一个整数 op。

如果 op=1,表示描述里的第 1 种要求,后面跟着三个整数 a,b,d。
如果 op=2,表示描述里的第 2 种要求,后面跟着三个整数 a,b,d。
如果 op=3,表示描述里的第 3 种要求,后面跟着两个整数 a,d。
如果 op=4,表示描述里的第 4 种要求,后面跟着两个整数 a,d。

Output
如果蒜头君能满足客人们的要求,输出最后一道菜的上菜时间;否则输出一行 'I can't'。

数据范围和约定

对于所有的数据:1≤n,m≤20000,1≤∣d∣≤10000 ,1≤a,b≤n,a≠b。

样例解释 1

1,2,3 的上菜时间分别为 0,2,12,这样能满足输入客人们的所有要求,并且时间最短。

Sample Input 1 

3
5
2 3 2 10
2 2 1 2
2 3 2 5
1 2 3 7
3 3 9
Sample Output 1

12
Sample Input 2 

3
4
3 1 3
2 3 1 9
2 1 3 -1
1 1 2 5
Sample Output 2

I can't
Sample Input 3 

17
20
2 6 3 -21
1 8 2 54
3 7 -95
4 11 44
1 5 15 40
3 9 1
3 3 30
3 8 23
2 9 12 -15
4 13 61
2 3 7 31
1 5 10 -15
2 16 1 43
2 12 3 -79
2 14 16 -51
3 6 48
4 7 0
2 10 11 -59
2 12 17 -29
3 4 10
Sample Output 3

77
 

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int maxn = 20010;

int n, m;

struct node {
	int v, w;
	node() { }
	node(int _v, int _w) {
		v = _v;
		w = _w;
	}
};

vector <node> g[maxn];
int dst[maxn];
queue <int> qu;
bool inq[maxn];
int cnt[maxn];
int flag;

void add(int u, int v, int w) {
	g[u].push_back(node(v, w));
	//	g[v].push_back(node());
}

void spfa(int u) {
	memset(inq, 0, sizeof inq);
	memset(dst, 0x80, sizeof dst);
	memset(cnt, 0, sizeof cnt);
	dst[u] = 0;
	qu.push(u);
	inq[u] = 1;
	cnt[u] = 1;
	while (!qu.empty()) {
		u = qu.front();
		qu.pop();
		inq[u] = 0;
		for (int i = 0; i<g[u].size(); i++) {
			int v = g[u][i].v;
			int w = g[u][i].w;
			if (dst[v]<dst[u] + w) {
				dst[v] = dst[u] + w;
				if (!inq[v]) {
					qu.push(v);
					inq[v] = 1;
					cnt[v]++;
					if (cnt[v]>n + 1) {
						return;
					}
					if (cnt[v] == n + 1) {
						flag = 1;
					}
				}
			}
		}
	}
	return;
}


int main() {
	cin >> n >> m;

	for (int i = 0; i<m; i++) {
		int d, a, b, c;
		cin >> d;
		if (d == 1) {
			cin >> a >> b >> c;
			g[a].push_back(node(b, c));
		}
		else if (d == 2) {
			cin >> a >> b >> c;
			g[b].push_back(node(a, c));
		}
		else if (d == 3) {
			cin >> a >> b;
			g[0].push_back(node(a, b));
		}
		else {
			cin >> a >> b;
			g[a].push_back(node(0, -b));
		}
	}

	for (int i = 1; i <= n; i++) {
		add(0, i, 0);
	}
	int ans = 0;
	spfa(0);

	if (flag) {
		cout << "I can't";
		return 0;
	}

	for (int i = 1; i <= n; i++) {
		ans = max(ans, dst[i]);
	}
	cout << ans;
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值