2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018)- D. Delivery Delays -二分+最短路+枚舉

2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018)- D. Delivery Delays -二分+最短路+枚舉


【Problem Description】

一座城市爲無向圖帶權圖,一號節點爲披薩餐廳的位置,有\(k\)我的定披薩,按時間前後順序給出定披薩的時間\(s_i\),地點\(u_i\)以及這我的的披薩在哪一個時間作好\(t_i\)。問在全部配送方案中,全部人的等待時間的最大值最小是多少?配送順序徹底按照先來先服務的原則node

【Solution】

首先求\(n\)\(Dijkstra\)求出任意兩點間配送所須要的最短路程時間是多少。而後二分答案\(t\),即假定全部人的等待時間的最大值爲\(t\),而後枚舉驗證便可。ios

由於配送順序按照先來先服務的原則,因此不一樣方案間惟一的區別就是:從餐廳出發後連續配送多少個訂單後回到餐廳。定義數組\(d[i]\)表示配送第\(i\)我的的訂單,並回到餐廳須要的最短期爲\(d[i]\)。對於第\(i\)個訂單,要麼連續配送\(1,2,\dots,i\),要麼連續配送\(2,3,\dots,i\),要麼\(\dots\),要麼直接配送\(i\),時間取最小值便可。因此直接\(O(n^2)\)枚舉便可。數組


【Code】

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define int long long
#define maxn 1005
#define maxm 5005
#define INF 1e15
namespace Dijkstra{
    struct node{
        int v,w,next;
        node(){}
        node(int v,int w,int next=-1):v(v),w(w),next(next){}
        bool operator <(const node&a)const{
            return w>a.w;
        }
    }g[maxm<<1];
    int head[maxn],cnt=0;
    bool vis[maxn];
    void init(){
        memset(head,-1,sizeof(head));cnt=0;
    }
    void addedge(int u,int v,int w){
        g[cnt]=node(v,w,head[u]);
        head[u]=cnt++;
    }
    int dis[maxn][maxn];
    void Run(int r,int n){
        for(int i=0;i<=n;i++) dis[r][i]=INF;dis[r][r]=0;
        memset(vis,0,sizeof(vis));
        priority_queue<node>q;
        q.push({r,0});
        while(!q.empty()){
            node now=q.top();q.pop();
            int u=now.v;
            if(vis[u]) continue;
            vis[u]=1;
            for(int i=head[u];~i;i=g[i].next){
                int v=g[i].v,w=g[i].w;
                if(!vis[v]&&dis[r][u]+w<dis[r][v]){
                    dis[r][v]=dis[r][u]+w;
                    q.push({v,dis[r][v]});
                }
            }
        }
    }
};
int s[maxn],u[maxn],t[maxn],dp[maxn];//第i我的的最短配送時間爲dp[i]
bool check(int mid,int k){
    for(int i=1;i<=k;i++) dp[i]=INF;dp[0]=0;
    for(int i=0;i<k;i++){
        int len=0/*配送路程*/,Min=INF/*最晚能在何時離開餐廳,同一批的取最小值*/,st=dp[i]/*離開餐廳的時間*/;
        for(int j=i+1;j<=k;j++){
            if(j==i+1) len+=Dijkstra::dis[1][u[j]];
            else len+=Dijkstra::dis[u[j-1]][u[j]];
            st=max(st,t[j]);
            Min=min(Min,mid-(len-s[j]));
            int delay=len+st-s[j];
            if(delay<=mid&&st<=Min) dp[j]=min(dp[j],st+len+Dijkstra::dis[u[j]][1]); //在知足條件的狀況下,才更新答案
            else break;
        }
    }
    return dp[k]<INF; //若是最後一個訂單都配送到了,則知足條件
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);Dijkstra::init();
    int n,m;cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v,w;cin>>u>>v>>w;
        Dijkstra::addedge(u,v,w);
        Dijkstra::addedge(v,u,w);
    }
    for(int i=1;i<=n;i++){
        Dijkstra::Run(i,n); //求任意兩個節點之間的最短路徑
    }
    int q;cin>>q;
    for(int i=1;i<=q;i++){
        cin>>s[i]>>u[i]>>t[i];
    }
    int left=0,right=1e15,mid,ans=INF;
    while(left<=right){ //二分答案
        mid=(left+right)>>1;
        if(check(mid,q)){
            right=mid-1;
            ans=min(ans,mid);
        }else{
            left=mid+1;
        }
    }
    cout<<ans<<endl;
    cin.get(),cin.get();
    return 0;
}
相關文章
相關標籤/搜索