POJ 3621 - Sightseeing Cows
找到一个圈,要求这个圈的点权和/边权和在所有的圈中最大,输出这个比率
设最大比率为ans ,∑V/∑E为一般的圈的比率k
最大的圈的k,即ans,>=所有的圈的k
即ans>=∑V/∑E
变形:∑(ans*E-V) > 0
图中边权改为ans*E-V (实际上不需要改边权,在使用时调整一下就行)(E是V的入边或者出边都可以)
二分ans,跑spfa
如果有负环 说明ans小了
没有负环 说明ans大了
最后注意控制精度在范围内
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<cstring>//ans*e[i]-v[i] #include<queue> using namespace std; const int maxn = 1007, maxm = 5007; const double inf = 1.0 * 0x3f3f3f3f; struct Edge{ int v, nxt; double w; Edge(){} Edge(int v, double w, int nxt):v(v), w(w), nxt(nxt){} }edge[maxm]; int n, m; int head[maxn], cnt[maxn], inq[maxn], tmp[maxn], tot; double d[maxn], mid; void addedge(int u, int v, double w){ edge[tot] = Edge(v, w, head[u]); head[u] = tot++; } bool spfa(int st){ for(int i = 0; i < maxn; i++) d[i] = inf; memset(cnt, 0, sizeof cnt); memset(inq, 0, sizeof inq); queue<int>Q; inq[st] = 1; d[st] = 0; Q.push(st); while(!Q.empty()){ int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = head[u]; ~i; i = edge[i].nxt){ int v = edge[i].v; double w = edge[i].w; w = mid*w-tmp[u]; if(d[v] > d[u]+w){ d[v] = d[u]+w; cnt[v] = cnt[u]+1; if(!inq[v]){ Q.push(v); inq[v] = 1; } if(cnt[v] > n){ return false; } } } } return true; }//0 -- 1e6 int main(){ while(scanf("%d%d", &n, &m)!=EOF){ tot = 0; memset(head, -1, sizeof head); for(int i = 1; i <= n; i++) scanf("%d", &tmp[i]); while(m--){ int u, v, w; scanf("%d%d%d", &u, &v, &w); addedge(u, v, w); } double l = 0, r = 1e6, ans = 0; while(r-l>0.0001){ mid = (l+r)/2; if(spfa(1)){ ans = mid; r = mid; } else l = mid; } printf("%.2lf\n", ans); } return 0; }