【问题描述】
背景
你知道吗,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;
}