Poj 1201 Intervals

题目链接:http://poj.org/problem?id=1201

差分约束系统。

我们用s[i]代表从[0,i]所含有的元素和

在本题中,如果[a,b]中有c个元素,那么:

s[b]-s[a-1]>=c,我们可以推得:s[a-1] - s[b] <= -c

同时,由于每一个值上最多只能含有一个元素,那么:

s[i] - s[i-1]<=1 

s[i] - s[i-1]>=0 推得:s[i-1] - s[i] <=0

这样:我们有了三个约束不等式:

s[a-1] - s[b] <= -c

s[i] - s[i-1]<=1 

s[i-1] - s[i] <=0

于是:

假设题目中所有查询的所在区间范围是:[start,end]的话,那么:

我们只要求出:s[end] -s[start-1] >= M就可以了。

其中M就是我们要的最小值。

我们可以整理成我们容易求解的形式:即:s[start-1] - start[end] <= -M

就是求从end这一点,到start-1这一点的最短路径。

然后求出的最短路径求相反数就是M了。

注意题目要求a可以为0,所有都++避免下标为负。Bellmanford会超时,spfa是首选。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stack>
#include <queue>
#include <algorithm>
#include <iostream>

using namespace std;

#define Maxn 50005
#define Maxm 200005
#define INF 0x3f3f3f3f

int first[Maxn];
int next[Maxm];
int total;
struct Edge
{
    int a,b;
    int w;
}edge[Maxm];

int dist[Maxn];
int vis[Maxn];
void init()
{
    total = 0;
    memset(first,-1,sizeof(first));
}
void addEdge(int a,int b,int w)
{
    edge[total].a = a,edge[total].b = b,edge[total].w = w;
    next[total] = first[a];
    first[a] = total++;
}
/*
bool bellmanFord(int start,int pointNum,int m)
{
    memset(dist,0x3f,sizeof(dist));
    dist[start] = 0;
    for(int i=0;i<pointNum-1;i++)
    {
        for(int j=0;j<m;j++)
        {
            int a = edge[j].a;
            int b = edge[j].b;
            int w = edge[j].w;
            if(dist[a] + w < dist[b]) dist[b] = dist[a] + w;
        }
    }
    for(int i=0;i<m;i++)
    {
        int a = edge[i].a;
        int b = edge[i].b;
        int w = edge[i].w;
        if(dist[a] + w < dist[b]) 
        {
            return false;
        }
    }
    return true;
}*/
int cnt[Maxn];
bool spfa(int s,int n)
{
    memset(dist,0x3f,sizeof(dist));
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    dist[s] = 0;
    queue<int> q;
    q.push(s);
    vis[s] = 1;
    while(!q.empty())
    {
        int temp = q.front();
        q.pop();
        vis[temp] = 0;
        for(int i=first[temp];i!=-1;i=next[i])
        {
            int a = edge[i].a;
            int b = edge[i].b;
            int w = edge[i].w;
            if(dist[a] + w < dist[b])
            {
                dist[b] = dist[a] + w;
                if(!vis[b])
                {
                    vis[b] = 1;
                    cnt[b]++;
                    if(cnt[b] > n) return false;
                    q.push(b);
                }
            }
        }
    }
    //判负环
    return true;
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int n;
    int a,b,c;
    int start,end;
    while(scanf(" %d",&n)!=EOF)
    {
        init();
        start = INF,end = -INF;
        for(int i=1;i<=n;i++)
        {
            scanf(" %d %d %d",&a,&b,&c);
            a++,b++;
            start = min(start,a);
            end = max(end,b);
            //b-a>=c -> a-b<=-c
            addEdge(b,a-1,-c);
        }
        for(int i=start;i<=end;i++)
        {
            //Si - Si-1 <= 1
            addEdge(i-1,i,1);
            //Si-1 - Si <= 0
            addEdge(i,i-1,0);
        }
        //if(!bellmanFord(end,end-start+2,total)) continue;
        if(!spfa(end,end-start+2)) continue;
        int ans = -dist[start-1];
        printf("%d
",ans);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/pangblog/p/3279754.html