POJ 1201 Intervals(差分约束-spfa)

Description
构造一个集合,这个集合内的数字需要满足所给的n个条件,每个条件都是指在[a,b]中至少有c个数在集合内,问这个集合最少包含多少个点
Input
第一行一整数n表示条件数,之后n行每行三个整数ai,bi,ci表示一个条件
(1<=n<=50000,1<=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
Solution
令T[i]表示在[0,i-1]内最少需要选的数,那么每个条件都可以转化为T[a]-T[b+1]<=-c,这是就考虑到差分约束了,但是条件还需要完善,因为每个数字最多选一次,最少不选,所以有0<=T[i]-T[i-1]<=1,即T[+1]-T[i]<=1,T[i]-T[i+1]<=0,之后用spfa求最短路即为答案,注意此题极限情况取条件中所有数字一定满足条件所以不需要构造超级源点也不需要判负环
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 55555
#define maxm 222222
struct edge
{
    int to,next;
    int cost;
}g[maxm];
int head[maxm],tol;
int dis[maxn];//所有点到起点的最短距离
int cnt[maxn];//统计每个点的入队次数,若入队次数大于顶点数说明有负环 
void init()//初始化 
{
    memset(head,-1,sizeof(head));
    tol=0;
}
void add(int u,int v,int c)//单向边,从u到v,权值为c 
{
    g[tol].cost=c;
    g[tol].to=v;
    g[tol].next=head[u];
    head[u]=tol++;
}
int spfa(int s,int n)//单源最短路,s是起点,n为点数 
{
    bool vis[maxn];
    memset(vis,false,sizeof(vis));
    memset(cnt,0,sizeof(cnt)); 
    queue<int>que;
    for(int i=0;i<maxn;i++)
        dis[i]=INF;
    cnt[s]++;
    dis[s]=0;
    vis[s]=true;
    que.push(s);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=head[u];i!=-1;i=g[i].next)
        {
            int v=g[i].to;
            int c=g[i].cost;
            if(dis[v]>dis[u]+c)
            {
                dis[v]=dis[u]+c;
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                    cnt[v]++;
                    if(cnt[v]>n)return 1;//存在负环 
                }
            }
        }
    }
    return 0;//不存在负环 
}
int main()
{
    int n,a,b,c,m;
    while(~scanf("%d",&n))
    {
        init();
        m=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b+1,-c);
            m=max(m,b);
        }
        m++;
        for(int i=0;i<m;i++)add(i+1,i,1),add(i,i+1,0);
        spfa(0,m+1);
        printf("%d\n",-dis[m]);
    }
    return 0;
}

你可能感兴趣的:(POJ 1201 Intervals(差分约束-spfa))