题意:
给你 n 个区间 [Ai, Bi],要求从每个区间中至少选出 Ci 个数出来组成一个序列
问:满足上面条件的序列的最短长度是多少?
解法:
对于 不等式 f(b)-f(a)>=c,建立 一条 b 到 a 的边 权值为 c,则求的最长路 即为 最小值(集合)
并且有隐含条件:0<=f(a)-f(a-1)<=1 则有边权关系(a,a-1,0)以及(a-1,a,-1);
一般地,差分约束系统分两类:求最大差和最小差
- 求最大差
建立形如 A-B<=C 的不等式,在原图中添加边 (B, A) 边权为 C ,对建好的图跑最短路,如果存在负环,无解(判断条件为某点被更新了 n 次),n 为图中点的数量 - 求最小差
建立形如 A-B>=C 的不等式,在原图中添加边 (B, A) 边权为 C ,对建好的图跑最长路,如果存在正环,无解(判断条件为某点被更新了 n 次),n 为图中点的数
//https://blog.csdn.net/lp_opai/article/details/46874659
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int inf = 99999999;
const int maxn = 50000 + 10;
struct edge {
int v, w;
};
vector<vector<edge>>a;
vector<int>dis(maxn, -inf);//最长路修改1
vector<bool>flag(maxn, false);
void add_edge(int u, int v, int w) {
edge tmp;
tmp.v = v;
tmp.w = w;
a[u].push_back(tmp);
}
void spfa(int s) {
queue<int>q;
q.push(s);
dis[s] = 0; flag[s] = true;
while (!q.empty()) {
int u = q.front(); q.pop(); flag[u] = false;
for (int i = 0; i < a[u].size(); i++) {
if (dis[a[u][i].v] < dis[u] + a[u][i].w) {//最长路修改2
dis[a[u][i].v] = dis[u] + a[u][i].w;
if (!flag[a[u][i].v]) {
q.push(a[u][i].v);
flag[a[u][i].v] = true;
}
}
}
}
}
int main() {
int n, m, aa = maxn, b = 0, c;
scanf("%d%d", &n, &m);
a.resize(maxn);
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
if (aa > u) aa = u;
if (b < v + 1) b = v + 1;
add_edge(u, v + 1, w);
}
for (int i = aa; i <= b; i++) {
add_edge(i, i - 1, -1);
add_edge(i - 1, i, 0);
}
spfa(aa);
printf("%d\n", dis[b]);
return 0;
}