(Div. 2, based on Olympiad of Metropolises)
题意:有n个地点,m次航班,每次航班有4个信息,起飞日期di、出发地fi、目的地ti、花费ci,起飞和出发地至少有一个是地点0。现在n个地点,每个地点有一个人,他们要到地点0,当所有人都到达的时候,一起待k天,然后再分别回到n个地点。问说最小的花费是多少,如果达不到这个要求输出-1。
参考博客:
http://blog.csdn.net/my_sunshine26/article/details/77876193
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
struct node
{
int d,u,v,c;
} data[999999];
int cmp(node a,node b)
{
return a.d<b.d;
}
long long vis[999999],ss[999999],tt[999999];
//第i天及以前能够全部到达0城市的最小花费ss[i],
//在第i天及以后能够全部离开0城市的最小花费tt[i]
int main()
{
int n,m,k;
cin>>n>>m>>k;
int max_day=0;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d%d",&data[i].d,&data[i].u,&data[i].v,&data[i].c);
max_day = max(max_day,data[i].d);
}
sort(data+1,data+1+m,cmp);
int cnt = n;
long long sum;
memset(vis,0,sizeof(vis));
for(int i=1; i<=m; i++)
{
if(data[i].u)//挑选出 u 0 的回家路线
{
int now = data[i].d;
if(!vis[data[i].u])
{
vis[data[i].u] = data[i].c;
cnt--;
if(cnt==0)
{
sum =0 ;
for(int i=1; i<=n; i++)
{
sum+=vis[i];
}
ss[now] = sum;
}
}
else if(vis[data[i].u]>data[i].c)
{
if(cnt==0)
{
sum-= vis[data[i].u];
sum+=data[i].c;
vis[data[i].u] = data[i].c;
ss[data[i].d] = sum;
}
else
vis[data[i].u] = data[i].c;
}
}
}
if(cnt!=0)
{
puts("-1");
return 0;
}
cnt = n;
memset(vis,0,sizeof(vis));
for(int i=m; i>=1; i--)
{
if(data[i].v)//挑选出 0 v 的回家路线
{
int now = data[i].d;
if(!vis[data[i].v])//假如当前还没有路线送这个人回去
{
vis[data[i].v] = data[i].c;
cnt--;
// cout<<data[i].v<<"&&&"<<endl;
if(cnt==0)
{
sum =0 ;
for(int i=1; i<=n; i++)
{
sum+=vis[i];
}
tt[now] = sum;
}
}
else if(vis[data[i].v]>data[i].c)
{
if(cnt==0)
{
sum-= vis[data[i].v];//此处非常重要,正是因为sum的继承,
//才会进行排序,从后往前扫描,使得最小值的更新有效
//此处会把所有 在路线中出现过的天数 算出符合要求的ss和tt结果
sum+=data[i].c;
vis[data[i].v] = data[i].c;
tt[data[i].d] = sum;
}
else
vis[data[i].v] = data[i].c;
}
}
}
if(cnt!=0)
{
puts("-1");
return 0;
}
// for(int i=1;i<=max_day;i++)
// {
// printf("%lld %lld\n",ss[i],tt[i]);
// }
// 顺序跑完之后再进行一边最小值的更新
//因为有可能这一天根本就没在路线中出现过
//但是这一天在符合要求的天数后边,确实还是符合要求,
//所以需要把这些天数给更新掉
for(int i=1; i<=max_day; i++)
{
if(!ss[i]) ss[i] = ss[i-1];
if(ss[i]&&ss[i-1])
ss[i] = min(ss[i],ss[i-1]);
}
for(int i=max_day; i>=1; i--)
{
if(!tt[i])tt[i] = tt[i+1];
if(tt[i]&&tt[i+1]) tt[i] = min(tt[i],tt[i+1]);
}
long long ans = 1e18;
//最后一班送专家回家的飞机时间为数据中出现的最大时间
for(int i=1; i<=max_day-k-1; i++)
{
if(ss[i]&&tt[i+k+1])//确保所有乘客都可以聚在一起且回去
ans = min(ans,ss[i]+tt[i+k+1]);
}
if(ans!=1e18) cout<<ans<<endl;
else puts("-1");
return 0;
}