差分约束,SPFA——POJ 1716

题目链接

题目含义

给出一堆区间,要求一个集合V与这些区间都共同含有两个以上不同的整数

题目分析

用sum[x]来表示[0,x]内包含V集合整数的个数

那么区间[a,b]则说明sum[b]-sum[a-1]>=2

在求最长路 if (dis[v]<dis[u]+w)  dis[v]=dis[u]+w;的这个式子,可以保证dis[v]>=dis[u]+w

也就是说这道题可以变成求最长路dis[mx]的距离

但有几点需要注意

(1)a-1是作为u来加边的,而head[u]明显不能让u小于0,而a又可以为0,所以最好把sum[b+1]-sum[a]作为

sum[b]-sum[a-1]

(2)本来想用Dijkstra写的,但发现用优先队列输出的是当前dis最小的,这样求最短路当然可以,但最长度就不知道行不行,干脆还是用SPFA吧

题目代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=1e4+7;
const int INF=0x3f3f3f3f;
typedef long long LL;
int head[maxn],dis[maxn];
bool vis[maxn];
int tot,n,a,b;
struct edge{
    int to,w,next;
}e[maxn*3];
//struct node{
//    int pos,dis;
//    bool operator<(const node &x)const{
//        return dis>x.dis;
//    }
//};
void add(int u,int v,int w){
    e[tot].to=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot++;
}
int max3(int a,int b,int c){
    return max(a,max(b,c));
}
void SPFA(){
    queue<int>q;
    dis[0]=0;
    vis[0]=true;
    q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=false;
        for(int i=head[u];i!=-1;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]){
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    tot=0;
    int mx=0;
    memset(head,-1,sizeof(head));
    memset(dis,-INF,sizeof(dis));
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a,&b);
        add(a,b+1,2);
        mx=max(mx,b+1);
    }
    for(int i=0;i<=mx;i++){
        add(i,i+1,0);
        add(i+1,i,-1);
    }
    SPFA();
    printf("%d\n",dis[mx]);
    return 0;
}

 

posted @ 2019-07-31 22:14  helman78  阅读(100)  评论(0编辑  收藏  举报