CF853B:
题意:
- 有n+1个城市,m个航班,n个城市的人到0城市开k天会,最后再回去。一天只有一趟航班。请问乘坐航班的最小费用。
题解:
- 如果乘坐价格便宜的航班,可能导致没有回来的航班。所以不能以价格排序。
- 如果乘坐早一点的航班,能准时到达,但是价格不是最优的。
正确解答:
- 枚举待在城市的k天,[l,l+k-1],求最小花费。
- 预处理第第i天前过去的最小花费,和第i天后回去的最小花费。
- 细节详见代码。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int const M = 100000 + 10;
int const K = 1000000 + 10; //总的天数
ll const inf = 1e18;
int n,m,k,cost[M],vis[M];
ll sum1[K],sum2[K];
struct FLY
{
int to,time,cost;
};
vector<FLY>v1,v2;
bool cmp1(FLY a,FLY b){
return a.time < b.time;
}
bool cmp2(FLY a,FLY b){
return a.time > b.time;
}
void Pre(vector<FLY>v,ll sum[K]){
memset(vis,false,sizeof(vis));
fill(sum,sum+K,inf); //记录i天之前的最小花费总和
int num = 0;
ll tot = 0;
for(int i=0;i<v.size();i++){
if(!vis[v[i].to]){ //如果这个地方之前没有来过
num++;
vis[v[i].to] = true;
tot += v[i].cost; //总费用
cost[v[i].to] = v[i].cost; //记录这个地方的费用
}else if(vis[v[i].to] && cost[v[i].to] > v[i].cost){ // 如果之前来过,比较费用
tot = tot - cost[v[i].to] + v[i].cost; //更新总费用
cost[v[i].to] = v[i].cost; //更新费用
}
if(num == n) //如果n座城市都去过了
sum[v[i].time] = tot;
}
}
ll solve(){
sort(v1.begin(),v1.end(),cmp1);
sort(v2.begin(),v2.end(),cmp2);
Pre(v1,sum1); Pre(v2,sum2);
for(int i=2;i<K;i++) sum1[i] = min(sum1[i],sum1[i-1]);
for(int i=K-2;i>=1;i--) sum2[i] = min(sum2[i],sum2[i+1]);
ll ans = inf;
for(int i=1;i+k<K;i++){
ans = min(ans,sum1[i-1]+sum2[i+k]);
}
return ans == inf ? -1 : ans;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
int time,from,to,cost;
cin>>time>>from>>to>>cost;
if(to == 0) //到0号城市
v1.push_back((FLY){from,time,cost});
else if(from == 0) //从0号出发
v2.push_back((FLY){to,time,cost});
}
printf("%lld\n",solve());
return 0;
}