WEEK8 作业A - 区间选点 II

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

输出一个整数表示最少选取的点的个数

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

题解

本题使用差分约束的方法解决,将差分约束中的不等式抽象成图。
结构体数组e用来存储所有边,int型数组head用来存储前向星链表,int型数组sum用来存储[0,i-1]之间选点的个数,vis数组记录该点是否位于队列中(防止重复进入队列)。mn和mx记录所有的点中的最小值和最大值(实际记录的是最大值+1)。
输入的a,b,c表示sum[b+1]-sum[a]>=c。因为0<=sum[i+1]-sum[i]<=1,所以sum[i+1]-sum[i]>=0,sum[i]-sum[i+1]>=-1。将这些不等式组都作为图中的边。这些不等式组都是>=,求该差分约束系统的最小解,跑最长路。
spfa遍历后,得到的sum[mx]即为最后结果。
易错点:一开始初始化的sum数组中元素都为0,这样导致了一些元素没有被遍历到(如:sum[2]和sum[4]都进过队列,但是在遍历sum[2](为0)和sum[4](为0或为1)时,检查到sum[3](也为0)的时候就不会再把3放进队列,这时如果有从3到8的约束条件就没有用上,就会出错),所以应该初始化的sum数组中元素都为-1。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <algorithm>
#include <queue>
using namespace std; 
int mn=100000,mx=-1;//最左边的点和最右边的点 
int head[50100];//前向星链表 
int sum[50100];// sum[i]表示[0,i-1]之间选点的个数 
int vis[50100];
struct edge{
	int to,nxt,w;
}e[200000];
int tot=0; 
void addEdge(int x,int y,int w){
	//cout<<tot<<":"<<x<<" "<<y<<" "<<w<<endl;
	e[tot].nxt=head[x];
	e[tot].to=y;
	e[tot].w=w;
	head[x]=tot;
	tot++;
} 
void init(){
	memset(head,-1,sizeof(head));
	memset(sum,-1,sizeof(sum));//注意 
	memset(vis,0,sizeof(vis));
}
void spfa(int s){
	queue<int>q;
	q.push(s);
	sum[s]=0;vis[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		vis[x]=0;
		for(int i=head[x];i!=-1;i=e[i].nxt){
			int y=e[i].to,w=e[i].w;
			if(sum[y]<sum[x]+w){
				sum[y]=sum[x]+w;
				if(vis[y]==0){
					q.push(y);
					vis[y]=1;
				}
			}
		}
	}
}
int main(int argc, char** argv) {
	init();
	int n;scanf("%d",&n);
	while(n--){
		int a,b,c;scanf("%d%d%d",&a,&b,&c);
		addEdge(a,b+1,c);
		if(a<mn){mn=a;}
		if(b+1>mx){mx=b+1;}
	}
	for(int i=mn;i<mx;i++){
		addEdge(i,i+1,0);
		addEdge(i+1,i,-1);
	}
	spfa(mn);
	printf("%d\n",sum[mx]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值