【图-差分约束】站队列比赛

  • 题目描述

    体育周即将结束,学校有一个事多的朱老师,提出了一个附加的活动项目,要求每个班
    按他的要求站队列, 比赛的结果不是按照队列站的是否整齐, 而是按他的要求展成的队列后,
    人数多少来评价。
    具体要求:
    1、在操场上画一条线,并在该线画上标号(1 到 n)
    2、事先不告诉队列的长度(即人数) ,但告诉在某些标号之间(区间)至少有多少个同
    学(同学只能站在标号上) ,用区间[ai,bi,ci]来描述它,[ai,bi,ci]表示在该队列中处于[ai,bi]这
    个区间的同学至少有 ci 个,现在给出若干个这样的区间,让每个班级按照这些区间要求去
    站队列,满足条件的队列长度最少的班级(即人数最少)为获胜班,小岳岳最后一次请求你
    的帮助。

  • 输入格式
    第一行包括一个整数 n(n≤1000) ,表示区间个数;
    以下 n 行每行描述这些区间,第 1+i 行三个整数 ai,bi,ci ,由空格隔开,其中 0≤ai
    ≤bi≤1000 而且 1≤ci≤bi-ai+1.
  • 输出格式
    只有一个整数表示满足要求队列长度的最小值,如果不存在则输出-1.
  • 样例输入

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

  • 样例输出

6

这题是从poj1201改的,加了一个输出-1。
传送门:poj1201

这题是一个挺弱的区间查分约束。
设d[i] 是第i位之前的最小值;
先根据题意给ai bi ci 满足 d[ai]-d[bi]>=c[i];
然后因为题中的(同学只能站在标号上) 有d[i+1]-d[i]>=0;
d[i+1]-d[i]<=1;

所以有:
d[ai]-d[bi]>=c[i];
d[i+1]-d[i]>=0;
d[i]-d[i+1]>=-1;
根据差分约束条件构图,用spfa跑最长路,判断负环时输出-1即可。
代码:

#include <iostream>
#include <queue>
#include <climits>
#include <cstdio>
#include <cstring>
#define INF 0xffffff
#define MAXARR 5000
#define WRONG -66666
using namespace std;
struct edge{
    int from,to,val;
};
vector<edge> e;
vector<int> node[MAXARR];
int n=0;
int MIN=INT_MAX,MAX=INT_MIN;
int s[MAXARR]={0};
void add_edge(int u,int v,int val)
{
    e.push_back((edge){u,v,val});
    node[u].push_back(n++);
}
int spfa()
{
    queue<int> q;
    int used[MAXARR]={0};
    int d[MAXARR]={0};
    fill(d+MIN,d+MAX,-INF);
    q.push(MIN);
    used[MIN]=1;
    d[MIN]=0;
    int sum[MAXARR];
    memset(sum,0,sizeof(sum));
    sum[MIN]++;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        used[u]=0;
        if(sum[u]>MAX)
            return WRONG;
        for(int i=0;i<node[u].size();i++)
        {
            if(d[e[node[u][i]].to]<d[u]+e[node[u][i]].val){
                d[e[node[u][i]].to]=d[u]+e[node[u][i]].val;
                if(!used[e[node[u][i]].to])
                {
                    used[e[node[u][i]].to]=1;
                    q.push(e[node[u][i]].to);
                    sum[e[node[u][i]].to]++;
                }
            }
        }
    }
    return d[MAX];
}
int main()
{
    int m;
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        MIN=min(a,MIN);
        MAX=max(b+1,MAX);
        add_edge(a,b+1,c);
    }
    for(int i=MIN;i<MAX;i++)
    {
        add_edge(i,i+1,0);
        add_edge(i+1,i,-1);
    }
    int temp=spfa();
    if(temp==WRONG) {cout<<-1<<endl;return 0;}
    cout<<temp<<endl;
    return 0;
}

p.s. 写题时边数组开小了。。。。RE了。。。。改成5000AC。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值