# POJ3621_Sightseeing Cows

题意:


给定一张有向图,每个点有权值 fun[i] ,每条边有权值 time[i]

要求找出一个环,使得环上所有点的点权和除以所有边的边权和最大

解:


首先,显然,这是一道01分数规划题

参照分数规划的套路

假定当前二分的值为 mid ,有环 S=({v}, {e}) ,环有 t 个点和 t 条边

考虑是否存在 S 使得

i=1t(midtimeifuni)<0S=({v}, {e})使mid<i=1tfunii=1ttimei

此时答案应该大于 mid

若不存在这样的 S ,则

S,midi=1tfunii=1ttimei

此时答案应该小于等于 mid

问题又来了,如何判断是否存在 S

有这样的办法:

在每次选定 mid 之后

新建一个与原图一样的图,但是没有点权,只有边权,并对边权值做如下修改

ei=edge(x > y),weight(x > y)=midtimeeifunx

这样建图有什么好处?

这样,若要判定 i=1t(midtimeifuni)<0 ,刚好对应图中存在“负环”

由此,在新建的图上跑SPFA,有负环说明 mid<i=1tfunii=1ttimei

没有则说明 midi=1tfunii=1ttimei

代码:


#include <bits/stdc++.h> using namespace std; const int N = 1010; const int M = 5010; int n, m; double l, r, mid, eps; int head[N], nxt[M], ver[M], tot; int thead[N], tnxt[M], tver[M], ttot; double tedge[M], edge[M], fun[N]; void add(int u, int v, double w) { ver[++tot] = v; edge[tot] = w; nxt[tot] = head[u]; head[u] = tot; } void tadd(int u, int v, double w) { tver[++ttot] = v; tedge[ttot] = mid * w - fun[u]; tnxt[ttot] = thead[u]; thead[u] = ttot; } void build() { memset(thead, 0, sizeof thead); memset(tnxt, 0, sizeof tnxt); memset(tver, 0, sizeof tver); memset(tedge, 0, sizeof tedge); ttot = 0; for (int i = 1; i <= n; i++) { int x = i; for (int j = head[x]; j; j = nxt[j]) { int y = ver[j]; tadd(x, y, edge[j]); } } } queue<int> q; double dis[N]; int cnt[N]; bool vis[N]; bool check() { while (q.size()) q.pop(); for (int i = 1; i <= n; i++) { vis[i] = true; q.push(i); dis[i] = cnt[i] = 0; } while (!q.empty()) { int x = q.front(); q.pop(); vis[x] = false; for (int i = thead[x]; i; i = tnxt[i]) { int y = tver[i]; double z = tedge[i]; if (dis[y] > dis[x] + z) { dis[y] = dis[x] + z; if (!vis[y]) { q.push(y); vis[y] = true; } cnt[y] = cnt[x] + 1; if (cnt[y] >= n) return true; } } } return false; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%lf", &fun[i]); for (int i = 1; i <= m; i++) { int u, v; double w; scanf("%d%d%lf", &u, &v, &w); add(u, v, w); } l = 0; r = 1000; eps = 0.000000000001; while (l + eps < r) { mid = (l + r) / 2; build(); if (check()) l = mid; else r = mid; } printf("%.2lf", l); return 0; }

__EOF__

本文作者熹圜
本文链接https://www.cnblogs.com/Xiwon/p/13394998.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   熹圜  阅读(80)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示