问题描述:
给定一个数轴上的 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个约束条件。每个约束条件是由两个其中的变量做差构成的,形如x2-x5≤1。
我们要解决的问题是:求一组解使得所有的约束条件得到满足,否则判断出无解。求解差分约束的解,都可以转换为求单源最短路问题。因为约束a-b<c可以转化为a<b+c;与我们单源最短路的松弛关系类似,因此可以使用求单源最短路的flyod,dijkstra算法等。
二、在这个题中,我们看到要求[a,b]中由c个点,如果sum[i]代表[0,i]区间里有多少个点,那么sum[b]-sum[a-1]>c就可以转化成sum[b]<sum[a-1]+c;同时,我们还需要保证1>=sum[i]-sum[i-1]>=0.将上述条件转化为边,插入到边集中。因为要求最小的点,所以我们使用spfa跑最长路,在跑的过程中,同时松弛,那么最后的位置的dis就是我们所选的点的个数。
完整代码:
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include<queue>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
const int inf=1e8;
struct edge{
int to;
int next;
int w;
}e[200001];
int head[50001],dis[50001],count[50001],inq[50001];
int tot=0;
void add(int x,int y,int w)
{
e[tot].to=y;
e[tot].next=head[x];
e[tot].w=w;
head[x]=tot;
tot++;
}
void init()
{
for(int i=0;i<50001;i++)
{
head[i]=-1;
dis[i]=-inf;
inq[i]=0;
}
}
int main(int argc, char** argv) {
int n;
cin>>n;
int max=0;
init();
for(int i=0;i<n;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b+1,c);
if(b+1>max)
max=b+1;
}
for (int i=1; i<=max; i++) {
add(i-1, i, 0);
add(i, i-1, -1);
}
int s=0;
dis[s] = 0;
inq[s] = 1;
queue<int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
inq[u] = 0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v = e[i].to;
if(dis[v] < dis[u] + e[i].w)
{
dis[v] = dis[u] + e[i].w;
if(!inq[v])
{
q.push(v);
inq[v] = 1;
}
}
}
}
cout<<dis[max]<<endl;
return 0;
}