【SPFA】遭遇战 VijosP1404

【问题描述】

背景

你知道吗,SQ Class的人都很喜欢打CS。(不知道CS是什么的人不用参加这次比赛)。
描述

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

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

【问题分析】

思路一:考场想到的用SPFA构出一张图来,然后跑最短路即可,不过需要注意的是每个时间都应该与前一个时间点连接一条权值为0的边,因为允许你选取带有重复部分的俩个区间,还有如果题中给出守卫区间(a,b)则应该连接a与b+1,因为dis[i]数组存储的是从s开始直到i秒全部守卫的最小代价。

思路二:dp 再加上一个线段树优化 这个没写出来 不过好像有很多大神。。

spfa代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <climits>
using namespace std;
const int N=10001;
const int T=90001;
const int inf=INT_MAX;
struct zk { int from,to,value,next; }edge[N+T];
int n,s,e,cnt;  int first[T];
queue<int> q; int dis[T];  bool used[T];
int readin()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void add(int a,int b,int c)
{
    cnt++;
    edge[cnt].from=a;  edge[cnt].to=b;
    edge[cnt].value=c;  edge[cnt].next=first[a];
    first[a]=cnt;
    return;
}
void read()
{
    int i,a,b,v;
    n=readin(); s=readin(); e=readin();
    for (i=1;i<=n;i++)
    {
        a=readin();
        b=readin();
        v=readin();
        if (b>=s||a<=e)
        {
            a=max(a,s);
            b=min(b,e);
            add(a,b+1,v);
        }
    }
    for (i=s;i<=e+1;i++)
    {
        add(i+1,i,0);
        dis[i]=inf;
    }
    return;
}
void spfa()
{
    int i,now;
    while(!q.empty()) q.pop();
    dis[s]=0; used[s]=1; q.push(s);
    while(!q.empty())
    {
        now=q.front();  q.pop();  used[now]=0;
        for (i=first[now];i;i=edge[i].next)
            if (dis[edge[i].to]>dis[now]+edge[i].value)
            {
                dis[edge[i].to]=dis[now]+edge[i].value;
                if (!used[edge[i].to])
                {
                    used[edge[i].to]=1;
                    q.push(edge[i].to);
                }
            }
    }
    if (dis[e]==inf)    printf("-1\n");
    else printf("%d\n",dis[e+1]);
}
int main()
{
    freopen("clean.in","r",stdin);
    freopen("clean.out","w",stdout);
    read();
    spfa();
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值