UVA11090 Going in Cycle!! 题解
题目大意
给定一个N个点M条边的带权有向图,求平均值最小的回路。
解法
看到这种题目,喜欢打暴力的我一下就想到:遍历整个图,找到每一个环,然后算出它们的平均值,最后比较出最小值。然而,呃...,会T飞...
既然我们不能暴力找最小值,那还有什么别的办法吗?
我们只需要输出一个最小值就行了,既然不能暴力遍历找环,那我们为何不能直接找答案呢?聪明的你一定想到了,找答案最一流(最高效)的,不就是二分答案吗?
确认了方向,接下来就是实现。
我们假设
首先:
通分一下:
移项一下:
稍微变一下:
这时,我们发现,环中的每一条边的边权减去
也就是说,我们把每一条边的边权减去我们猜的答案
于是乎,
做到这里,我们就基本已经做完了这道题,接下来就可以看看我丑陋的代码了。
AC Code
#include<bits/stdc++.h> using namespace std; const int N = 55; struct node { int y; double w; }; int T, t, n, m, cnt[N]; double dis[N]; bool vis[N]; vector<node> a[N]; void init() { for(int i = 1; i <= n; i++) a[i].clear(); return; } bool spfa(double s) { memset(cnt, 0, sizeof(cnt)); memset(vis, false, sizeof(vis)); queue<int> q; for(int i = 1; i <= n; i++)//由于题目不保证图连通,所以是多起点SPFA { dis[i] = 0; q.push(i); vis[i] = true; } while(!q.empty()) { int x = q.front(); q.pop(); vis[x] = false; int len = a[x].size(); for(int i = 0; i < len; i++) { int y = a[x][i].y; double w = a[x][i].w - s;//注意这里边权要减去猜的答案 if(dis[x] + w < dis[y]) { dis[y] = dis[x] + w; cnt[y] = cnt[x] + 1; if(cnt[y] >= n) return true; if(vis[y]) continue; q.push(y); vis[y] = true; } } } return false; } void slove() { cin >> n >> m; init(); double lt = 1e9, rt = -1e9; for(int i = 1; i <= m; i++) { int x, y; double w; cin >> x >> y >> w; a[x].push_back((node){y, w}); lt = min(lt, w), rt = max(rt, w);//取左边界和右边界 } lt--, rt++; double q = rt;//处理无解的情况准备的 while(lt + 1e-6 < rt)//注意精度问题 { double mid = (lt + rt) / 2; if(spfa(mid)) rt = mid; else lt = mid; } if(q == rt)//判断是否无解 printf("Case #%d: No cycle found.\n", ++t);//注意输出格式 else printf("Case #%d: %.2f\n", ++t, rt); return; } int main() { cin >> T; while(T--) slove(); return 0; }
完结撒花★,°:.☆( ̄▽ ̄)/:.°★ 。★,°:.☆( ̄▽ ̄)/:.°★ 。
本文作者:Luckies
本文链接:https://www.cnblogs.com/Luckies/p/UVA11090.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步