zoukankan      html  css  js  c++  java
  • bzoj4898 & loj2308 [Apio2017]商旅 最短路+01分数规划

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=4898

    https://loj.ac/problem/2308

    题解

    发现我们可以把整个环路分成很多段,每一段都携带着一个物品。

    那么从 (x)(y) 的这一段,我们可以预处理出应该选择什么物品。可以发现这个是不会变化的。

    于是我们可以视为问题转化为了这样一个问题:给定一个有向完全图,每一条边有一个价值 (w),还有一个费用 (t),选择一个环,使得 (frac{sum w}{sum t}) 最大。

    这显然是一个分数规划的模型,于是直接二分,每条边的边权是一个 (w-midcdot t),只需要判断有没有非负的环就可以了,可以使用 (spfa)


    代码如下,时间复杂度为 (nmlog W)

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 100 + 7;
    const int M = 10000 + 7;
    const int K = 1000 + 7;
    const int INF = 0x3f3f3f3f;
    const ll INF_ll = 0x3f3f3f3f3f3f3f3f;
    
    int n, m, k, maxw, hd, tl;
    int b[N][K], s[N][K]; // b = buy, s = sell
    int f[N][N], w[N][N];
    int num[N], q[N], inq[N];
    ll dis[N], g[N][N];
    
    inline void floyd() {
    	for (int k = 1; k <= n; ++k)
    		for (int i = 1; i <= n; ++i)
    			for (int j = 1; j <= n; ++j)
    				if (i != j) smin(f[i][j], f[i][k] + f[k][j]);
    }
    
    inline void ycl() {
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= n; ++j)
    			for (int l = 1; l <= k; ++l) if (~s[j][l] && ~b[i][l]) smax(w[i][j], s[j][l] - b[i][l]);
    }
    
    inline void qpush(int x) { ++tl; tl == N ? tl = 1 : 0; q[tl] = x; }
    inline int qhead() { ++hd; hd == N ? hd = 1 : 0; return q[hd]; }
    
    inline bool spfa() {
    	hd = tl = 0;
    	for (int i = 1; i <= n; ++i) dis[i] = -INF_ll, inq[i] = 0, num[i] = 0;
    	dis[1] = 0, qpush(1), inq[1] = 1;
    	while (hd != tl) {
    		int x = qhead();
    		inq[x] = 0;
    		for (int y = 1; y <= n; ++y) if (y != x && dis[y] <= dis[x] + g[x][y]) {
    			dis[y] = dis[x] + g[x][y], num[y] = num[x] + 1;
    			if (num[y] >= n) return 1;
    			if (!inq[y]) qpush(y), inq[y] = 1;
    		}
    	}
    	return 0;
    }
    
    inline bool check(const int &mid) {
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= n; ++j)
    			g[i][j] = w[i][j] - (ll)mid * f[i][j];
    	return spfa();
    }
    
    inline void work() {
    	floyd();
    	ycl();
    	int l = 0, r = maxw;
    	while (l < r) {
    		int mid = (l + r + 1) >> 1;
    		if (check(mid)) l = mid;
    		else r = mid - 1;
    	}
    	printf("%d
    ", l);
    }
    
    inline void init() {
    	read(n), read(m), read(k);
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= k; ++j)
    			read(b[i][j]), read(s[i][j]);
    	int x, y, z;
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= n; ++j)
    			if (i == j) f[i][j] = 0;
    			else f[i][j] = INF;
    	for (int i = 1; i <= m; ++i) read(x), read(y), read(z), smin(f[x][y], z), smax(maxw, z);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    windows7 下 apache2.4 和 php5.5 及 mysql5.6 的安装与配置
    JavaScript高级编程 (1)
    关于解决乱码问题的一点探索之二(涉及Unicode(utf-16)和GBK)
    关于解决乱码问题的一点探索之一(涉及utf-8和GBK)
    Windows上安装、配置MySQL的常见问题
    解析DXF图形文件格式
    vue三十一:vue配置反向代理
    vue三十:eslint修复错误和打包用于生产
    vue二十九:多个文件组件集成
    vue二十八:Vue-Cli之环境搭建之node安装脚手架和使用脚手架创建vue项目
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj4898.html
Copyright © 2011-2022 走看看