POJ1201/ZOJ1508/HDU1384 Intervals(spfa解差分约束问题)

来源:互联网 发布:淘宝一元秒杀网址 编辑:程序博客网 时间:2024/05/01 01:21

题意是说给出一些闭区间,这些区间上整点可以选择放一个元素或者不放,但是每个区间都有一个下限,就是说你在这个区间里面的元素个数不能低于这个下限值。

最后要求出最少需要几个元素才能满足每个区间的要求。

建图(参见这里)之后可以转化成最长路问题。

另:差分约束中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:busing 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[]赋初值为0memset(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;}


原创粉丝点击