vijos p1404遭遇战

2 篇文章 0 订阅
1 篇文章 0 订阅

[spfa][区间问题]
背景
你知道吗,SQ Class的人都很喜欢打CS。(不知道CS是什么的人不用参加这次比赛)。
描述
今天,他们在打一张叫DUSTII的地图,万恶的恐怖分子要炸掉藏在A区的SQC论坛服务器!我们SQC的人誓死不屈,即将于恐怖分子展开激战,准备让一个人守着A区,这样恐怖分子就不能炸掉服务器了。(一个人就能守住??这人是机械战警还是霹雳游侠?)
但是问题随之出现了,由于DustII中风景秀丽,而且不收门票,所以n名反恐精英们很喜欢在这里散步,喝茶。他们不愿意去单独守在荒无人烟的A区,在指挥官的一再命令下,他们终于妥协了,但是他们每个人都要求能继续旅游,于是给出了自己的空闲时间,而且你强大的情报系统告诉了你恐怖份子计划的进攻时间(从s时刻到e时刻)。

当然,精明的SQC成员不会为你免费服务,他们还要收取一定的佣金(注意,只要你聘用这个队员,不论他的执勤时间多少,都要付所有被要求的佣金)。身为指挥官的你,看看口袋里不多的资金(上头真抠!),需要安排一个计划,雇佣一些队员,让他们在保证在进攻时间里每时每刻都有人员执勤,花费的最少资金。
格式
输入格式
第一行是三个整数n(1≤n≤10000),s和e(1≤s≤e≤90000)。

接下来n行,描述每个反恐队员的信息:空闲的时间si, ei(1≤si≤ei≤90000)和佣金ci(1≤ci≤300000)。

输出格式
一个整数,最少需支付的佣金,如果无解,输出“-1”。

样例1
样例输入1
3 1 5
1 3 3
4 5 2
1 1 1
样例输出1[复制]
5
限制

提示

敌人从1时刻到4时刻要来进攻,一共有3名反恐队员。第1名从1时刻到3时刻有空,要3元钱(买糖都不够??)。以此类推。

一共要付5元钱,选用第1名和第2名。

来源
SQ CLASS公开编程竞赛2008——Problem D
Source: WindTalker, liuichou, royZhang

题目思路
这道题的题目可以这样概括,有一个区间[s,t],然后有一些小区间,来覆盖整个区间,可以转成求最短路径,这里我用SPFA。
可是这样其实建图很难建,
几个易错误的地方:
1.比如第一个反恐队员,可以守[1,6],但是6过后时间其他队员的钱可能比一个[3,~],还要多,所以这个队员守的过程中是可以换用其他反恐队员的,,。[很垃圾的我做的时候并没有想到这个很坑爹的地方,然而这个地方却是这道题最巧妙的一个地方。QAQ]
处理方法

for(int i = s; i<=e+1;i++){
ed[++tot]=ii(i,head[i+1],0);
head[i+1]=tot;}

每一个都建一条反边回去,代价即为0,i+1到i的边,这样的意思就相当于这个时刻,其他队员即使开始时间在这个时刻前面也可以跳回去用这个更优的队员。
2.这道题给的数据范围是n[1,10000],时刻点是[1,90000],这个范围一定要注意,开边应该至少开成[90000+10000],n个人的边加上90000个时刻的反边,这里的节点是时刻,,不要弄成人了。,有些别人的代码边开的很大,,其实[90000+10000]就够了。
3.因为这是区间,不是单纯的点,最好的处理区间的方法就是加一个1,什么意思,1__2__3__4__5__6,比如这是一个区间,求[1,5],但是这里的时刻其实是一个“__”,所以其实点的话是[1,6].
……..原谅我说了这么多,我只是越写越觉得这道题很好QAQ…………


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define LL long long
#define cle(x) memset(x,0,sizeof(x))
#define maxcle(x) memset(x,127,sizeof(x))
#ifdef WIN32
#define AUTO "%I64d"
#else 
#define AUTO "%lld"
#endif
using namespace std;
const int N=90050,INF=0x3f3f3f3f,M=10050;
int n,s,e;
struct ii{
    int to,ne,v;
    ii(int to=0,int ne=0,int v=0):to(to),ne(ne),v(v){ }
}ed[N+M];//记住不是N,节点是时间节点
int head[N],tot;
inline int readin(){
    int res=0;
    char ch;
    while((ch = getchar())>'9'||ch<'0');
    res=ch-'0';
    while((ch = getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return res;
}
void init(){
    n=readin(),s=readin(),e=readin();
    for(int i = 1; i<= n; i++){
        int x=readin(),y=readin(),z=readin();
        if(x<=e&&y>=s){
            x=max(s,x),y=min(e+1,y+1);//区间加一
            ed[++tot]=ii(y,head[x],z);
            head[x]=tot;
        }
    }
    for(int i = s; i<=e+1;i++){
        ed[++tot]=ii(i,head[i+1],0);
        head[i+1]=tot;}//建反边,!!!!可以中途换其他人使其更优
}
bool inq[N];
LL dis[N];
queue<int>q;
void spfa()
{
    q.push(s),inq[s]=1;
    maxcle(dis);
    dis[s]=0;
    bool flag=false;
    while(!q.empty()){
        int u=q.front();q.pop(),inq[u]=false;
        for(int i=head[u];i;i=ed[i].ne){
            int v=ed[i].to;
            if(dis[v]>dis[u]+ed[i].v){
                dis[v]=dis[u]+ed[i].v;
                if(v==e+1)flag=true;
                if(!inq[v]){
                    inq[v]=true;
                    q.push(v);
                }                   
            }
        }
    }
    if(!flag)printf("-1\n");
    else printf(AUTO,dis[e+1]);
}
int main(){
    freopen("vijos.in","r",stdin);
    freopen("vijos.out","w",stdout);
    init();
    spfa();
    return 0;
}

。。。祝您AC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值