题目描述:
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点
使用差分约束系统的解法解决这道题(前面用贪心解决过)
Input:
输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。
Output:
输出一个整数表示最少选取的点的个数
sample input:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
sample output:
6
个人思路:
什么是差分系统?
- 差分约束是一种特殊的n元一次不等式组,它包含n个变量和m个约束条件。
- 每个约束条件都是由两个系数为1的变量的差构成的,类似:Xi - Xj <= Ck,Ck是常数;
- 而这种约束条件类似于最短路中的松弛条件,Xi <= Ck + Xj ;
解的存在性:
上界和下界问题:
- 因为最短路是根据等于号来求解的,此时跑最短路得到的是最大解(上界),如果想要最小解(下界),则将<=变成>=然后跑最长路即可。
代码块:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 5e4 + 5;
const int inf = 1e9;
struct edge {
int v, w;
edge(int x, int y) { v = x, w = y; }
};
int n, a[maxn], b[maxn], c[maxn], inq[maxn], cnt[maxn], dis[maxn];
vector<edge>G[maxn];
queue<int>q;
void adde(int u,int v,int w) {
G[u].push_back(edge(v, w));
}
void spfa(int s) {
dis[s] = 0;
inq[s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop(); inq[u] = 0;
int siz = G[u].size();
for (int i = 0; i < siz; ++i) {
int v = G[u][i].v, w = G[u][i].w;
if (dis[v] < dis[u] + w) {
dis[v] = dis[u] + w;
if (!inq[v]) {
q.push(v);
inq[v] = 1;
}
}
}
}
}//xi - xj >= ck
int main() {
scanf("%d", &n);
int maxb = 0;
for (int i = 0; i < maxn; ++i)dis[i] = -inf, cnt[i] = 0, inq[i] = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d", &a[i], &b[i], &c[i]);
if (b[i] + 1 > maxb)maxb = b[i] + 1;
}
for (int i = 1; i <= n; ++i) {
adde(a[i], b[i] + 1, c[i]);
}
for (int i = 0; i < maxb; ++i) {
adde(i, i + 1, 0);
adde(i + 1, i, -1);
}
spfa(0);
cout << dis[maxb] << endl;
return 0;
}