A - 区间选点 II
题目:
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点
使用差分约束系统的解法解决这道题
使用差分约束系统的解法解决这道题
使用差分约束系统的解法解决这道题
使用差分约束系统的解法解决这道题
使用差分约束系统的解法解决这道题
Input
输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。
Output
输出一个整数表示最少选取的点的个数
思路:
这一题上一次做还是用的贪心,这一次则要使用差分约束来做这一题。使用差分来做的话首先需要做的就是分析里面的差分约束式子。令 sum[ i ]为0 - i的点的数目,则 “ [ai, bi] 里至少有 ci 个点 ” 这句话可转换为
sum[ bi ] - sum[ ai ]>= ci
又,对其中每一个点,有
0 <= sum[ i+1 ] - sum[ i ] <= 1
因此,依据上面的式子加以变形,我们就可以得到一组差分约束的不等式。然后再借用spfa和dijktra中松弛条件的特性,将不等式组转换为图,如:a - b<= c -> a <= b + c 说明b到a有一条权值为c的边。在根据不等式组构造出图以后,使用spfa或dijstra跑最长路。总区间最右端点到0点的距离即为最终结果。这里要注意的是ai可能为0,将所有点右移一位来确保不会出现数组越界的情况。
代码:
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
int dis[50100];
int vis[50100];
struct node
{
int element;
int weight;
};
vector<node> G[50100];
void init()
{
for(int i=0;i<50100;i++)
{
dis[i]=-1000;
vis[i]=0;
}
}
int main()
{
init();
int n;
scanf("%d",&n);
int maxP=0;
for(int i=0;i<n;i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
x++;y++;
node temp;
if(y>maxP)
maxP=y;
temp.element=y;temp.weight=z;
G[x-1].push_back(temp);
}
node temp;
for(int j=0;j<maxP;j++)
{
temp.element=j+1;temp.weight=0;
G[j].push_back(temp);
}
for(int j=1;j<=maxP;j++)
{
temp.element=j-1;temp.weight=-1;
G[j].push_back(temp);
}
queue<int> q;
q.push(0);
dis[0]=0;
vis[0]=1;
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0