BZOJ4669 抢夺(网络流)

BZOJ4669 抢夺(网络流)

题目描述

大战将至, 美国决定实行计划经济。美国西部总共有 N 个城市,编号为 0 ∼ N − 1,以及 M 条道路,道路是单向的。其中城市 0 是一个大城市,里面住着 K 个人,而城市 N − 1 是一个农业城市。现在所有城市 0 的居民都需要到城市 N − 1 去领取食物。由于担心体力不支,所以居民都会采取开车的形式出行。但道路不是无限宽的,对于一条道路,会有 ci 的限制,表示在同一天内,最多只能有 ci 辆车同时在这条道路上行驶。一条道路的长度为 1,每辆车的行驶速度也可以假定为 1 每天。城市 N − 1 会在每个居民都到达后马上开始发放食物。现在 Reddington 想知道,假如在最优安排下,居民最早能在多少天后领到食物。假如没有居民那就不需要发放食物,默认为第 0 天。

数据范围

\(1 \le N \le 1000, 1 \le M \le 5000, 0 \le K \le10^9\)
\(0 \le u, v \lt N, 1 \le ci \le 109,数据组数不超过 10 组\)

解题思路

不太一样的题目

首先一眼网络流并有了一个非常暴力的思路,将图按时间分层跑最大流,但事实上太慢了跑不过去

给一个新奇的做法

贪心的想肯定是走最短路好啊,但最短路可能会拥挤,会有很多人等待导致答案不优,如果我们选择多条较短路一起走呢

设当前所有路径的流量和是 \(f\),走完最长的“较短路”要用时间 \(t\) ,t 时间过后所有人都按着这些路径每天都可以走流量的人

考虑每次增广一条路径,上次的路径长度是 \(T'\),这次路径长度是 \(T\),那么走完这次路径新增的人是 \((T-T')*sum\)

代码

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template<typename F>
inline void write(F x)
{
	static short st[30];short tp=0;
	if(x<0) putchar('-'),x=-x;
	do st[++tp]=x%10,x/=10; while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar('\n');
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }

const int N = 100500;
int h[N], ne[N<<1], to[N<<1], w[N<<1], cost[N<<1], tot = 1, m, n, k;

inline void add(int x, int y, int z, int c) {
	ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z, cost[tot] = c;
}


const ll inf = 0x3f3f3f3f3f3f3f3f;
ll dis[N], vis[N], fr[N];
queue<int> q;
bool spfa(void) {
	memset(dis, 0x3f, sizeof(dis));
	q.push(1), dis[1] = 0;
	while (q.size()) {
		int x = q.front(); q.pop(); vis[x] = 0;
		for (int i = h[x], y; i; i = ne[i]) {
			if (!w[i] || dis[y = to[i]] <= dis[x] + cost[i]) continue;
			fr[y] = i; dis[y] = dis[x] + cost[i];
			if (!vis[y]) vis[y] = 1, q.push(y);
		}
	}
	return dis[n] < inf;
}

void work(void) {
	if (k == 0) return puts("0"), void();
	ll ans = inf, las = 0, sum = 0;
	while (k > 0 && spfa()) {
		ll f = inf;
		for (int t = n ; fr[t]; t = to[fr[t] ^ 1]) Mn(f, (ll)w[fr[t]]);
		for (int t = n ; fr[t]; t = to[fr[t] ^ 1]) w[fr[t]] -= f, w[fr[t] ^ 1] += f;
		k -= f + (dis[n] - las) * sum, sum += f, las = dis[n];
		Mn(ans, dis[n] + ((k - 1) / sum) + 1);
	}
	if (ans < inf) write(ans); else puts("No solution");
}

 
 
int main() {
	while (scanf ("%d %d %d\n", &n, &m, &k) != EOF) {
		tot = 1; memset(h, 0, n * 4 + 200);
		for (int i = 1, x, y, z;i <= m; i++) {
			read(x), read(y), read(z), x++, y++;
			add(x, y, z, 1), add(y, x, 0, -1);
		}
		work();
	}
	return 0;
}

/*

2 1 1
0 1 555

*/
posted @ 2020-06-12 16:13  Hs-black  阅读(134)  评论(0编辑  收藏  举报