Week8—A—区间选点(差分求解)

3 篇文章 0 订阅
2 篇文章 0 订阅

题目描述:

给定一个数轴上的 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值