题意是说给出一些闭区间,这些区间上整点可以选择放一个元素或者不放,但是每个区间都有一个下限,就是说你在这个区间里面的元素个数不能低于这个下限值。
最后要求出最少需要几个元素才能满足每个区间的要求。
建图(参见这里)之后可以转化成最长路问题。
另:差分约束中dist[ ]的初始化很有意思,比如你初始化的是 0 ,那么按照最长路更新dist[ ]数组,最后得到的就是大于 0 的最小值;如果按照最短路更新dist[ ]的话,最后结果是小于 0 的最大值。 ——LC
还有,针对这种差分约束问题建图转化成为最短路问题的处理,很多 blog 的建图都是为了队列入队操作时方便,加入了一个虚点,这个虚点和图中每一个点都连一条权值为 0 的边,开始寻找最长路时,首先把这个虚点入队。其实我们可以省略这个点,这样的话,我们需要手动把图中每个点入队,同时把他们的dist[ ]值更新成 0 ,听着有点麻烦是吧,不过的确是个省时间的办法,至于优化效果怎么样,就不好说了。 ——LC
我的代码:
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<climits>
#define find_min(a,b) a<b?a:b
#define find_max(a,b) a>b?a:b
using namespace std;
const int N = 50010;
struct Edge{
int s,e,v;
int next;
}edge[N];
int n,e_num,p_num,vis[N],head[N],dist[N];
int left_x,right_x;
void AddEdge(int a,int b,int c){
edge[e_num].s=a;
edge[e_num].e=b;
edge[e_num].v=c;
edge[e_num].next=head[a];
head[a]=e_num++;
}
queue <int>q;
void spfa(){
while(!q.empty()){
int cur=q.front();
q.pop();
vis[cur]=0;
for(int i=head[cur];i!=-1;i=edge[i].next){
int u=edge[i].e;
if(dist[u] < dist[cur]+edge[i].v){
dist[u]=dist[cur]+edge[i].v;
if(!vis[u]){
q.push(u);vis[u]=1;
}
}
}
if(cur>left_x && dist[cur]-1 > dist[cur-1]){
dist[cur-1]=dist[cur]-1;
if(!vis[cur-1]){
q.push(cur-1);vis[cur-1]=1;
}
}
if(cur<right_x && dist[cur] > dist[cur+1]){
dist[cur+1]=dist[cur];
if(!vis[cur+1]){
q.push(cur+1);vis[cur+1]=1;
}
}
}
printf("%d\n",dist[right_x]);
}
void getmap(){
int i,a,b,c;
e_num=p_num=1;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
left_x=INT_MAX; right_x=INT_MIN;
for(i=1;i<=n;i++){
scanf("%d%d%d",&a,&b,&c);
AddEdge(a,b+1,c);//可能存在a==b的情况
left_x=find_min(left_x,a);
right_x=find_max(right_x,b+1);
}
//省略掉那个虚点,可以优化spfa.虚点作用是让所有点入队,且dist[]更新为0,
//所以省略掉这点的话,需要手动把所有点入队,dist[]赋初值为0
memset(dist,0,sizeof(dist));
for(i=left_x;i<=right_x;i++){
q.push(i);vis[i]=1;
}
}
int main(){
while(~scanf("%d",&n)){
getmap();
spfa();
}
return 0;
}