算法刷题记录(Day 30)

本文通过两个实例介绍如何运用差分系统结合SPFA算法解决区间覆盖问题及信息可靠性判断问题,详细展示了算法实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Intervals(poj 1201)

原题链接
题目类型:差分系统

解题思路:
假设s[i]代表的是从0到i-1所能选择的点的个数,则对于ai,bi,ci有以下式子成立s[bi+1]-s[ai]>=ci
同时,1>=s[i+1]-s[i]>=0
需要注意的是,本题要求求解s[i]的最小值。
我们知道,对于xa-xb<=xc,xa-x0<=w,求得的解是满足条件xi<=w的最大值,若设置w为0,那么xi即为最大的负数,即最小的正数。这也是本题的要求。

为此,将上述不等式转化为:
s[ai]<=-ci+s[bi+1]
s[i+1]<=1+s[i]
s[i]<=0+s[i+1]
s[i]<=0+s[x0]

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define ABMAX 55000
#define INF 0x3f3f3f3f
int h[ABMAX];
struct edge {
	int from, to, nxt, w;
};
vector<edge> E;
int num = 0;
int n, ai, bi, ci;
int dst[ABMAX], inq[ABMAX];
void addline(int from, int to, int weight) {
	edge cur;
	cur.from = from, cur.to = to, cur.w = weight, cur.nxt = h[from];
	h[from] = E.size();
	E.push_back(cur);
}
void spfa(int s) {
	queue<int> Q;
	memset(dst, INF, sizeof(dst));
	memset(inq, 0, sizeof(inq));
	dst[s] = 0, inq[s] = 1;
	Q.push(s);
	while (!Q.empty()) {
		int x = Q.front();
		Q.pop();
		for (int i = h[x]; i != -1; i = E[i].nxt) {
			int y = E[i].to;
			if (dst[y] > dst[x] + E[i].w) {
				dst[y] = dst[x] + E[i].w;
				if (!inq[y]) Q.push(y);
			}
		}
	}
}
int main() {
	cin >> n;
	memset(h, -1, sizeof(h));
	for (int i = 0; i < n; i++) {
		cin >> ai >> bi >> ci;
		if (bi + 1 > num) num = bi + 1;
		addline(bi + 1, ai, -ci);
	}
	for (int i = 0; i <= num; i++) {
		addline(num + 1, i, 0);
		if (i != num) {
			addline(i + 1, i, 0);
			addline(i, i + 1, 1);
		}
	}

	spfa(num + 1);
	cout << -dst[0] << endl;
}

需要注意的是,最后不应该输出dst[num],而应该输出dst[0]

//2022.6.10更新
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define ABMAX 55000
#define INF 0x3f
int h[ABMAX];
struct edge {
	int from, to, nxt, w;
};
vector<edge> E;
int num = 0;
int n, ai, bi, ci;
int dst[ABMAX], inq[ABMAX];
void addline(int from, int to, int weight) {
	edge cur;
	cur.from = from, cur.to = to, cur.w = weight, cur.nxt = h[from];
	h[from] = E.size();
	E.push_back(cur);
}
void spfa(int s) {
	queue<int> Q;
	memset(dst, -INF, sizeof(dst));
	memset(inq, 0, sizeof(inq));
	dst[s] = 0, inq[s] = 1;
	Q.push(s);
	while (!Q.empty()) {
		int x = Q.front();
		Q.pop();
		inq[x] = 0;
		//cout << Q.size() << endl;
		for (int i = h[x]; i != -1; i = E[i].nxt) {
			int y = E[i].to;
			if (dst[y] < dst[x] + E[i].w) {
				dst[y] = dst[x] + E[i].w;
				if (!inq[y]) {
					inq[y] = 1;
					Q.push(y);
				}
			}
		}
	}
}
int main() {
	cin >> n;
	memset(h, -1, sizeof(h));
	for (int i = 0; i < n; i++) {
		cin >> ai >> bi >> ci;
		if (bi > num) num = bi;
		addline(ai-1, bi, ci);
	}
	for (int i = 1; i <= num; i++) {
		//addline(0, i, 0);
		addline(i - 1, i, 0);
		addline(i, i - 1, -1);
	}

	spfa(0);
	cout << dst[num] << endl;
}

Is the Information Reliable?(poj 2983)

原题链接
解题思路:对于等于号,例如a-b=c,建立a-b>=c和a-b<=c两个不等式。转化为差分系统之后,使用spfa判定负权环的方式进行是否存在解的判断(松弛次数超过点数)。

//tle
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define NMAX 1100
#define INF 0x3f3f3f3f
int h[NMAX];
struct edge {
	int from, to, nxt, w;
};
vector<edge> E;
int N, M;
int dst[NMAX], inq[NMAX], out[NMAX];
void addline(int from, int to, int weight) {
	edge cur;
	cur.from = from, cur.to = to, cur.w = weight, cur.nxt = h[from];
	h[from] = E.size();
	E.push_back(cur);
}
int spfa(int s) {
	queue<int> Q;
	memset(dst, INF, sizeof(dst));
	memset(inq, 0, sizeof(inq));
	memset(out, 0, sizeof(out));
	dst[s] = 0, inq[s] = 1;
	Q.push(s);
	while (!Q.empty()) {
		int x = Q.front();
		Q.pop();
		for (int i = h[x]; i != -1; i = E[i].nxt) {
			int y = E[i].to;
			if (dst[y] > dst[x] + E[i].w) {
				out[y]++;
				if (out[x] >= N+1) {
					return 0;
				}
				dst[y] = dst[x] + E[i].w;
				if (!inq[y]) Q.push(y);
			}
		}
	}
	return 1;
}
int main() {
	while (scanf_s("%d %d",&N,&M)==2) {
		memset(h, -1, sizeof(h));
		getchar();
		E.clear();
		//if (!N && !M) break;
		for (int i = 0; i < M; i++) {
			char c = getchar();
			if (c == 'P') {
				int a, b, c;
				cin >> a >> b >> c;
				addline(a, b, c);
				addline(b, a, -c);
				getchar();
			}
			else if (c == 'V') {
				int a, b;
				cin >> a >> b;
				addline(b, a, -1);
				getchar();
			}
			else cout << "WA";
		}
		for (int i = 1; i <= N; i++) {
			addline(0, i, 0);
		}
		if (spfa(0))cout << "Reliable" << endl;
		else cout << "Unreliable" << endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值