zoukankan      html  css  js  c++  java
  • GYM 101933D(最短路、二分、dp)

    要点

    • 非要先来后到暗示多源最短路,求最小的最大值暗示二分
    • 二分内部的check是关键,dp处理一下,(dp[i])表示第(i)笔订单最早何时送达,如果在ddl之前到不了则(return 0)。我觉得其中(time)变量的维护很好地使复杂度降了一维。
    • 第一发WA点:算法看了一遍感觉没有可改的,就把二分的(r)调大了,又把(longlong)的输入输出改为流,莽试一发就过了……
    #include <cstdio>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 1005, maxm = 5005;
    const ll INF = 1e18;
    
    int n, m, k;
    ll s[maxn], u[maxn], t[maxn];
    struct Edge {
    	int to, nxt, cost;
    }e[maxm << 1];
    int head[maxn], tot;
    ll dis[maxn][maxn];
    
    void add(int u, int v, int c) {
    	e[++tot].to = v, e[tot].cost = c, e[tot].nxt = head[u], head[u] = tot;
    }
    
    void dij(int st) {
    	for (int i = 1; i <= n; i++)	dis[st][i] = INF;
    	dis[st][st] = 0;
    	
    	typedef pair<ll, int> pli;
    	priority_queue<pli, vector<pli>, greater<pli>> Q;
    	Q.push({0, st});
    
    	while (Q.size()) {
    		ll d = Q.top().first;
    		int p = Q.top().second;
    		Q.pop();
    		if (d > dis[st][p])	continue;
    		for (int i = head[p]; i; i = e[i].nxt) {
    			int t = e[i].to;
    			if (dis[st][t] > d + e[i].cost) {
    				dis[st][t] = d + e[i].cost;
    				Q.push({dis[st][t], t});
    			}
    		}
    	}
    }
    
    bool ok(ll D) {
    	ll dp[maxn];
    	dp[0] = 0;
    	for (int i = 1; i <= k; i++)
    		dp[i] = INF;
    	for (int i = 1; i <= k; i++) {
    		ll val = dis[1][u[i]];
    		ll st = max(t[i], dp[i - 1] + dis[u[i - 1]][1]);
    		dp[i] = min(dp[i], st + val);
    		if (dp[i] > s[i] + D)	return 0;
    
    		ll time = s[i] + D - st - val;
    		if (time < 0)	continue;
    		for (int j = i + 1; j <= k; j++) {
    			val += dis[u[j - 1]][u[j]];
    			if (t[j] > st) {
    				time -= t[j] - st;
    				st = t[j];
    			}
    			time = min(time, s[j] + D - st - val);
    			if (time < 0)	break;
    			dp[j] = min(dp[j], st + val);
    		}
    	}
    	return 1;
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1, u, v, c; i <= m; i++) {
    		scanf("%d %d %d", &u, &v, &c);
    		add(u, v, c), add(v, u, c);
    	}
    	scanf("%d", &k);
    	for (int i = 1; i <= k; i++)
    		cin >> s[i] >> u[i] >> t[i];
    
    	for (int i = 1; i <= n; i++) {
    		dij(i);
    	}
    	ll l = 0, r = 1e18, ans;
    	while (l <= r) {
    		ll mid = (l + r) >> 1;
    		if (ok(mid))	r = mid - 1, ans = mid;
    		else	l = mid + 1;
    	}
    	cout << ans << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    WPF窗口和用户控件事件相互触发
    C#排序算法总结
    C#.NET操作数据库通用类
    在C#的WPF程序使用XAML实现画线
    centos7 用户介绍
    Linux系列2
    nginx的使用
    TCP协议、三次握手以及滑动窗口等的介绍(计算机网络基础知识)
    mysql的
    jQuery的东西
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10867128.html
Copyright © 2011-2022 走看看