区间选点
给定一个数轴上的 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
我的思路:
这道题就是求满足所有区间的最小选点数,这里使用的是差分约束的方法,然后结合最短路SPFA算法解决。根据题目的描述,可以将问题转化一下,[a,b]之间有k个点,可以转化为存在(a-1)->b的边,且权值为-k。将所给区间全部转化结束后,还要讲相邻的点之间连通,即(i-1)->i,权值为0;i->(i-1),权值为1。(要满足sum[a]-sum[a-1]<=1,其中sum为最短路算法中的dis,即a之前的点的个数)。在构造完图之后,因为负权值,所以直接跑一个SPFA就可以了,结果就是所有区间最大的边界的sum值(这里要记得取相反数,因为计算权值时用的是负数权值)。
我的总结:
这次的实验让我对于SPFA算法有了更加深刻的了解,同时,也让我了解到了差分约束在实践中的应用。最后,一定要记得在加完题干所给的边之后,再在每个相邻节点间加边,而且要满足题干的相邻小于1要求。
我的代码:
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#define inf 1e9
using namespace std;
const int maxn = 6e6+5;
const int maxx = 15e4+20;
struct Edg
{
long long to,next,w;
}edg[maxn];
long long n,dis[maxx],bb=-1,aa=inf,a,b,wi,ind=0,head[maxx],inq[maxx];
queue<long long > que;
void add(long long x,long long y,long long wei)
{
edg[++ind].to=y;
edg[ind].next=head[x];
edg[ind].w=wei;
head[x]=ind;
}
void init()
{
for(long long i=0;i<maxx;i++)
{
dis[i]=inf;
inq[i]=0;
head[i]=0;
}
}
void SPFA()
{
que.push(aa);
dis[aa]=0;
inq[aa]=1;
while(!que.empty())
{
long long o=que.front();
que.pop();
inq[o]=0;
for(long long i=head[o];i;i=edg[i].next)
{
long long v=edg[i].to;
long long ww=edg[i].w;
if(dis[v] > dis[o]+ww){
dis[v]=dis[o]+ww;
if(!inq[v])
{
que.push(v);
inq[v]=1;
}
}
}
}
}
int main()
{
cin>>n;
init();
while(n--)
{
cin>>a>>b>>wi;
add(a-1,b,-wi);
aa=min(aa,a-1);
bb=max(bb,b);
}
for(long long i=aa+1;i<=bb+1;i++)
{
add(i-1,i,0);
add(i,i-1,1);
}
SPFA();
//for(long long i=aa;i<=bb;i++) cout<<i<<" "<<dis[i]<<endl;
cout<<-dis[bb]<<endl;
return 0;
}