POJ 1201 Intervals (差分约束) - from lanshui_Yang

          题目大意:给你 n 个区间[ai , bi] (1 <= i <= n) ,和 n 个数ci ,让你找出一个集合 Z, 使得对于所有的i (1 <= i <= n)来说, Z 中的数字 在 区间[ai , bi] 中个数 >= ci ,找出包含元素个数最少的 集合 Z , 并输出其大小 。

          解题思路:这是一道差分约束题,设 s[ i ] 表示集合Z中 小于等于 数字 i 的元素个数,则由题意得出如下约束条件:

     1、对于所有的[ai , bi] , 有 s[ bi ] - s[ai - 1] >= ci ,变换后得s[ ai - 1 ] - s[bi] <=  - ci 。

     2、s[ i ] - s[ i - 1 ] >= 0 ,变换后得 s[ i - 1] - s[ i ] <= 0

     3 、s[ i ] - s[ i - 1] <= 1 ,变换后得 s[ i - 1 ] - s[ i ] <=  -1  

根据约束条件建立有向图,以所有 bi 的 最大值 maxn 为源点 , 求出源点到达其他各点的最短路 ,设所有ai 中的最小值 Min ,那么 -1 * dist[ Min - 1 ] 就是所求答案。

请看代码:

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#define mem(a , b) memset(a , b , sizeof(a))
using namespace std ;
const int MAXN = 15e4 + 5 ;
const int INF = 0x7fffffff ;
struct Edge
{
    int adj ;
    int d ;
    int next ;
} e[MAXN] ;
int head[MAXN] ;
int dist[MAXN] ;
bool inq[MAXN] ;
int ecnt ;
int Min , Maxn ;
int n ;
void chu()
{
    mem(head , -1) ;
    ecnt = 0 ;
}
void init()
{
    int i ;
    Min = INF ;
    Maxn = -1 ;
    for(i = 0 ; i < n ; i ++)
    {
        int a  , b , c ;
        scanf("%d%d%d" , &a , &b , &c) ;
        a ++ ;
        b ++ ;
        if(Min > a) Min = a ;
        if(Maxn < b) Maxn = b ;
        c *= (-1) ;

        e[ecnt].adj = a - 1 ;
        e[ecnt].d = c ;
        e[ecnt].next = head[b] ;
        head[b] = ecnt ;
        ecnt ++ ;

    }
    for(i = Min ; i <= Maxn ; i ++)
    {
        e[ecnt].adj = i ;
        e[ecnt].d = 1 ;
        e[ecnt].next = head[i - 1] ;
        head[i - 1] = ecnt ;
        ecnt ++ ;

        e[ecnt].adj = i - 1 ;
        e[ecnt].d = 0 ;
        e[ecnt].next = head[i] ;
        head[i] = ecnt ;
        ecnt ++ ;
    }
}
queue<int> q ;
void spfa(int u)
{
    mem(inq , 0) ;
    while (!q.empty()) q.pop() ;
    q.push(u) ;
    inq[u] = 1 ;
    int tmp ;
    while (!q.empty())
    {
        tmp = q.front() ;
        q.pop() ;
        inq[tmp] = 0 ;
        int i ;
        for(i = head[tmp] ; i != -1 ; i = e[i].next)
        {
            int v = e[i].adj ;
            int td = e[i].d ;
            if(dist[tmp] != INF && dist[tmp] + td < dist[v])
            {
                dist[v] = dist[tmp] + td ;
                if(!inq[v])
                {
                    q.push(v) ;
                    inq[v] = 1 ;
                }
            }
        }
    }
}
void solve()
{
    int i ;
    for(i = Min - 1 ; i <= Maxn ; i ++)
    {
        dist[i] = 0 ;
    }
    dist[Maxn] = 0 ;
    spfa(Maxn) ;
    printf("%d\n" , -1 * dist[Min - 1]) ;
}
int main()
{
    while (scanf("%d" , &n) != EOF)
    {
        chu() ;
        init() ;
        solve() ;
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值