NCPC2018 Delivery Delays

 

题意:你经营着一家披萨店,该披萨店在1号点,每天都会有很多的订单,第i个订单是在si时刻发来的,收货地点在ui,该披萨在ti时刻才可以做好。问你每个订单的收货时间-发出时间(即买家等待时间)的最大值 的最小值 是多少。

即用dp[i]表示第i个订单,让你最小化 Max{dp[i]-s[i]}

数据输入:

第一行:n(点的数目,n<=1000),m(边的数目,m<=5000)

接下来m行: x,y,z (表示从xy直接有一条双向边,长度0=

接下来一行:k(订单数目,k<=1000)

接下来k行:si,ui,ti(描述意义如上,0<=ti<=si<=1e8

Solution

 

要最小化 最大值,一般通过二分来确定,我们在这里二分这个等待时间

Part1 预处理出来每个点到其余点的最小距离,n遍dij即可

Part 2 判断这个等待时间是否可行

  考虑用dp来算出来到达第i号订单的点的最快时间

  因为可以屯着送披萨,我们就可以把这个送订单分成若干份若干份的送,可以考虑把  i号订单起连续到j号订单一起送,然后到      达第j号订单的最短时间,j+1号订单的出发  时间必须>=送达第j号订单的时间+从j号订单的点回到1号点的时间。

  即第i号订单的出发时间为max(dp[i-1]+dis[1][u[i-1]],t[i]);

  那么就开始dp,首先记第i号订单的出发时间为statime,那么,送到i号订单时间  就  是statime+dis[1][u[i]],如果想把第i+1个订    单和第i个一起送,那么,出发时间就得变  成max(statime,t[i+1]),但到达第i个点的时间不会再提前了,就不用更新dp[i]了,此    时判断把i+1和i一起送会不会超出等待时间,如果会,就不再连着送了,如果不会,  就可以得到到达i+1号订单的时间了,更新    这个dp[i+1],以及连着送过程重的最大等  待时间。

  因为从不同的点连着送到达i会得到不同的dp[i],所以要以每个点为起点跑一遍那个  dp过程

  时间复杂度O(k²)

  Part 3 二分

 这个应该不用说了,但是这道题的数据比较毒瘤,首先观察每条边的权值,发现最小值会是0,再观察订单的si和ti,会发现si可   能等于ti,即不需要等待就可以拿到pizza,被瞬间转移限制想象力,观察数据可得二分下限为0,上限为1e15

总时间复杂度O( n*n*log(e)  k*k*log(1e15) )

#include
using namespace std;
const int maxn = 1010;
struct node{
    long long u,to,w;
}edge[10010];
struct di{
    long long u, w;
    di(long long _u=0, long long _w=0):u(_u),w(_w){}
    bool friend operator < (di da, di db){
        return da.w (di da, di db){
        return da.w>db.w;
    }
}ex;
long long head[maxn], cnt;
long long dis[maxn][maxn], s[maxn], u[maxn], t[maxn], dp[maxn], mista[maxn];
int n,m,k;
inline void add(long long x, long long y, long long w){
    cnt++;  edge[cnt].u=y;  edge[cnt].w=w;  edge[cnt].to=head[x];   head[x]=cnt;
    return ;
}
inline void get_dis(long long uu){
    priority_queue< di, vector, greater >q;
    q.push(di(uu,0));
    cnt=0;
    long long tu, tw;
    while(!q.empty()){
        ex=q.top(); q.pop();
        if (dis[uu][ex.u]0;i=edge[i].to){
            tu=edge[i].u;   tw=ex.w+edge[i].w;
            if (tw x){
            continue;
        }
        dp[i]=min(dp[i],exdis);
        for (int j=i+1;j<=k;++j){
            if (statime>=t[j]){
                exdis = exdis + dis[u[j-1]][u[j]];
                wtime = max(wtime , exdis - s[j] );
            }else{
                exdis = exdis + dis[u[j-1]][u[j]] + t[j] - statime;
                wtime = max(wtime + t[j]-statime , exdis - s[j] );
            }
            statime=max(statime,t[j]);
            if (wtime>x){
                break;
            }
            dp[j]=min(exdis,dp[j]);
        }
    }
    if (dp[k]==1e18){
        return false;
    }
    return true;
}
void sol(){
    long long l,r,mid;
    l=0;    r=1e18;
    if (pj(0)){
        puts("0");
        return ;
    }
    while(l>1;
        if (pj(mid)){
            r=mid;
            if (l+1==r){
                break;
            }
        }else{
            l=mid;
            if (l+1==r){
                break;
            }
        }
    }
    if (pj(l)){
        r=l;
    }
    printf("%lld\n",r);
    return ;
}
int main(){
    read_init();
    dp[0]=0;   t[0]=0;     u[0]=1;
    sol();
    return 0;
}

 

 

你可能感兴趣的:(DP,二分)