程序设计思维Week8-作业
A-区间选点II
Description
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点。
使用差分约束系统的解法解决这道题
输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。
输出一个整数表示最少选取的点的个数
Sample
Input:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
Output:
6
Idea
前提:使用差分约束解决问题,根据不等式组形成图,用前向星存储图
- 构造不等式组
记sum[i]表示数轴上[0,i]之间选点的个数。对于第i个区间[ai,bi]需要满足sum[b+1]-sum[a]>=C,即sum[b+1]>=C+sum[a],a指向b+1的边权重为C,每次存储边,同时更新最左边界和最右边界
需要约束单位区间至多选一个点,即0<=sum[i+1]-sum[i]<=1,i指向i+1的边权重为0,i+1指向i的边权重为-1,从最左边界至最右边界,对每个单位区间添加这两条边 - 由题得到的不等式组都是>=,求该差分约束系统的最小解,跑最长路
使用SPFA求解从最左边界出发到达最右边界的最长路 - SPFA遍历后,获得dis[最右边界]即总共最少要选的点
Summary
区间选点I的方法是按右端点排序后贪心
区间选点II的方法是差分约束系统构建图+SPFA
图中有负权边,利用SPFA求解最长路径只需改变一个判断条件。
存边时可以将[a,b]转化成[a,b+1),权重是每个区间至少需要的点个数。记录最左边界和最右边界,以确定SPFA的起点以及终点对应的dis。约束每个单位区间至多选一个点。
T了几次,原因是遍历前向星的边时陷入死循环,应该是中断条件不对,改成头指针都初始化为0可以解决。
时间复杂度平均为O(km)
Codes
#include <iostream>
#include <queue>
using namespace std;
const int inf = 1e10;
int n,sum[50020],dis[50020],vis[50020],inq[50020],head[50020],tot=0, bmax=-1,amin=inf;
struct edge {
int u,v,w, next;
}e[200020];
void add(int u,int v,int w) {
e[++tot].u = u;
e[tot].v = v;
e[tot].w = w;
e[tot].next = head[u];
head[u] = tot;
}
void init() {
tot = 0;
for (int i = 0; i <= n; i++) {
dis[i] = -inf;
vis[i] = 0;
head[i] = 0;
}
}
void spfa(int s) {
queue<int> q;
for (int i = 0; i <= n; ++i)
dis[i] = -inf, vis[i] = 0;
q.push(s);
dis[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = 0;
for (int i = head[u]; i != 0; i = e[i].next) {
//cout << "k";
int v = e[i].v,w=e[i].w;
if (dis[v] < dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
//if (t.next == -1)break;
}
}
}
int main()
{
cin.sync_with_stdio(false);
cin >> n;
init();
//sum[0] = 0;
for (int i = 1; i <= n; i++) {
int a, b,c;
cin >> a >> b >> c;
//scanf("%d%d%d", &a, &b, &c);
add(a, b+1, c);
if (bmax < b+1)bmax = b+1;
if (amin > a)amin = a;
}
for (int i = amin; i < bmax; i++) {
add(i, i+1, 0);
add(i+1, i , -1);
}
spfa(amin);
cout << dis[bmax] << endl;
}