差分约束(例区间选点

差分约束系统定义

一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式
(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)

解释:其实就是一堆不等式,然后求出一组解。
不等式形如 Xi-Xj<=Ck  (i!=j)
然后我们需要求出一组解X1~Xn有{A1~An},而对于常数d,{A1+d~An+d}也是它的
一组解,因为做差可以将d消除

在这里插入图片描述
在这里插入图片描述

差分约束与SPFA

 利用差分约束解决问题的时候,我们常常把它化为求最短路径问题,因为要把不等
 式化为我们想要的形式,所以常常会有负数,即是会出现负边权的问题,
所以Floyd和Dijkstra通常无法解决,我们就用Bellman-Ford算法来解决此类问题。

常见的不等式转换
在这里插入图片描述

区间选点问题

给定一个数轴上的 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

分析:之前用贪心算法写过此题。对于差分约束解决此题的具体过程
我们不妨把ai bi看为dis[v[i]]和dis[u[i]],从而转化为图中的点,
求解最少的选取点的个数,就是最短路径的问题,满足每个区间至少有Ci
个点,设置这个区间权值为Ci,那么dis[v[i]]-dis[u[i]]>=ci,实现了路径压缩。

Codes

#include<iostream>
#include<queue>
using namespace std;
const int Inf=-1e6;
const int maxn=1e5;
int vis[maxn],head[maxn],tot=0,dis[maxn],n,a,b,c,ma=maxn,mb=0;
struct edge{
 int to,next,w;
};
edge e[maxn*2];
queue<int> Q;
//ci<=bi-ai+1
//构造为  -bi<=-(ai-1)+(-ci) 
void Init(){//初始化 
 for(int i=0;i<maxn;i++){
  head[i]=0;
  vis[i]=0;
  dis[i]=Inf;
 }
 while(!Q.empty()) Q.pop();
}//链式前向星 
void add_edge(int u,int v,int w){
 e[++tot].to=v;
 e[tot].next=head[u];
 e[tot].w=w;
 head[u]=tot;
} 
void spfa(int s){
 dis[s]=0;vis[s]=1;
 Q.push(s);//起点入队
 while(!Q.empty()){
  int u=Q.front();Q.pop();
  vis[u]=0;
  for(int i=head[u];i!=0;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(vis[v]==0){
     Q.push(v);
     vis[v]=1;
    }
   }
  }
 }
}
int main(){
 ios::sync_with_stdio(false);
 cin>>n;
 Init();
 for(int i=0;i<n;i++){
  cin>>a>>b>>c;
  add_edge(a,b+1,c);//让a从0开始,实际上是右端点包含
  //所以有c<=b-a+1,也可以构造add_edge(a,b+1,c)
  //dis[b]-dis[a-1]>=c or dis[b+1]-dis[a]>=c 
  ma=min(a,ma);
  mb=max(b+1,mb);
 }//0<=dis[i+1]-dis[i]<=1
 for(int i=ma;i<=mb;i++){
  add_edge(i,i+1,0);
  add_edge(i+1,i,-1);
 }
 spfa(ma);
 cout<<dis[mb]<<endl;
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值