题意:
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [
a
i
a_i
ai,
b
i
b_i
bi] 里至少有
c
i
c_i
ci 个点。
输入格式:
输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。
输出格式:
输出一个整数表示最少选取的点的个数
输入样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
输出样例:
6
思路:
用sum[i]表示数轴上[0, i] 之间选点的个数,对于第 i 个区间,sum[
b
i
b_i
bi] - sum[
a
i
a_i
ai] >=
c
i
c_i
ci,而且对于任意 i > 0,0 <= sum[i] - sum[i - 1] <= 1。
这两个式子可以类比差分约束标准式
x
i
x_i
xi -
x
1
x_1
x1 <= T 类似,所以可以使用差分约束来解决问题。
对于sum[
b
i
b_i
bi] - sum[
a
i
a_i
ai - 1] >=
c
i
c_i
ci,可以变形为有向边
a
i
a_i
ai-1->
b
i
b_i
bi,权值为
c
i
c_i
ci。0 <= sum[i] - sum[i - 1] <= 1,可以变形为有向边 i-1->i,边权为0,以及 i->i-1,边权为-1。
构造出有向加权图之后,对该图进行spfa操作,得到sum[bMax],并输出。
注意事项:
a
i
a_i
ai>=0,所以
a
i
a_i
ai-1可能小于0,所以有向边构造时,需要把
a
i
a_i
ai-1->
b
i
b_i
bi改为
a
i
a_i
ai->
b
i
b_i
bi+1。
代码:
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct edge {
int to, weight;
edge(){}
edge(int t, int w) {
to = t;
weight = w;
}
};
int inf = (int)1e9;
const int N = 50005;
vector<edge> g[N];
int dis[N], inq[N];
int mx = 0, mn = inf;//所有区间的最右边界和最左边界
int n;
void spfa(int x) {
//初始化
memset(dis, 0, sizeof(dis));
memset(inq, 0, sizeof(inq));
//队列
queue<int> q;
//第一个元素入队
q.push(x);
dis[x] = 0;
inq[x] = 1;
//循环,取出队列中的front,进行判断
while (q.size()) {
//取出front
int now = q.front(); q.pop(); inq[now] = 0; //cout << now <<" ";
//每次取出now指向的第i个点
for (int i = 0; i < g[now].size(); i++) {
int y = g[now][i].to;
int w = g[now][i].weight;
//判断修改
if (dis[y] == 0 && dis[now] == 0 && w == 0){
if (!inq[y]) {
q.push(y);
inq[y] = 1;
}
}
if (dis[y] < dis[now] + w) {
dis[y] = dis[now] + w; //cout << y << " " << dis[y] << endl;
//判断入队
if (!inq[y]) {
q.push(y);
inq[y] = 1;
}
}
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a].push_back(edge(b + 1, c));
mn = min(a, mn);
mx = max(b + 1, mx);
}
for (int i = mn; i < mx; i++) {
g[i].push_back(edge(i + 1, 0));
g[i + 1].push_back(edge(i, -1));
}//cout << mn << mx << endl;
spfa(mn);
cout << dis[mx];
}