• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
01分数规划

01分数规划

题目

观光奶牛

思路

​ 在图论问题中,求(一堆的和 / 一堆的和)这样的问题我们称之为\(01\)分数规划,一般我们都采用二分来做。

​ \(\frac{\sum f_i}{\sum t_i}\) , 其中\(f_i\)表示点权,\(t_i\)表示边权。

\[\frac{\sum f_i}{\sum t_i} > mid \\ \sum f_i > mid \sum t_i \\ \sum f_i - mid \sum t_i > 0 \\ \sum (f_i - mid\times t_i) > 0 \\ \]

​ 我们再将边权置为\(w(u \rightarrow v) = f_u - mid \times t_{u, v}\),check函数就可以写成图中是否存在正环来判断是否为true, 由于判断的是存在,我们只需要求最长路即可。

​ 这里需要注意一下,求负环是否存在我们用最短路, 求正环是否存在我们用最长路,既保证尽量小和尽量大。

​ 最后,确定答案区间,我们只需要二分答案即可。

Code

#include <iostream>
#include <queue>
#include <cstring>

using i64 = long long;

const int N = 1100, M = 1e4 + 10;

int n, m;

int h[N], e[M], ne[M], t[M], f[N], idx;

double dist[N];

int cnt[N];

bool st[N];

void add(int a, int b, int c) {
	ne[idx] = h[a], h[a] = idx, e[idx] = b, t[idx ++] = c;
}
	
bool spfa(double mid) {
	memset(dist, 0, sizeof dist);
	memset(cnt, 0, sizeof cnt);
	memset(st, 0, sizeof st);

	std::queue<int> q1;

	for (int i = 1; i <= n; i ++) {
		q1.push(i);
		st[i] = true;
	}

	while (q1.size()) {
		int u = q1.front(); q1.pop();

		st[u] = false;

		// std::cout << u << "\n";

		for (int i = h[u]; ~i; i = ne[i]) {
			int v = e[i];

			if (dist[v] < dist[u] + (f[u] - t[i] * mid)) {
				dist[v] = dist[u] + (f[u] - t[i] * mid);
				cnt[v] = cnt[u] + 1;
				
				if (cnt[v] >= n) {
					return true;
				}
				
				if (!st[v]) {
					q1.push(v);
					st[v] = true;
				}
			}
		}
	}

	return false;
}

int main() {
	memset(h, -1, sizeof h);

	std::cin >> n >> m;

	for (int i = 1; i <= n; i ++) std::cin >> f[i];

	for (int i = 1; i <= m; i ++) {
		int a, b, c;

		std::cin >> a >> b >> c;

		add(a, b, c);
		// add(b, a, c);
	}

	// for (int i = 1; i <= n; i ++) {
	// 	add(0, i, 0);
	// }

	double l = 0, r = 1e6;

	while (r - l > 1e-4) {
		double mid = (l + r) / 2;

		if (spfa(mid)) l = mid;
		else r = mid;
	}

	printf("%.2lf", l);
}
posted on 2023-04-21 20:11  Jack404  阅读(16)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3