题意是说给出一些闭区间,这些区间上整点可以选择放一个元素或者不放,但是每个区间都有一个下限,就是说你在这个区间里面的元素个数不能低于这个下限值。
最后要求出最少需要几个元素才能满足每个区间的要求。
建图(参见这里)之后可以转化成最长路问题。
另:差分约束中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; }