题目:http://poj.org/problem?id=3621
Sightseeing Cows
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12563 Accepted: 4259
Description
Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to spend their free time.
Fortunately, they have a detailed city map showing the L (2 ≤ L ≤ 1000) major landmarks (conveniently numbered 1… L) and the P (2 ≤ P ≤ 5000) unidirectional cow paths that join them. Farmer John will drive the cows to a starting landmark of their choice, from which they will walk along the cow paths to a series of other landmarks, ending back at their starting landmark where Farmer John will pick them up and take them back to the farm. Because space in the city is at a premium, the cow paths are very narrow and so travel along each cow path is only allowed in one fixed direction.
While the cows may spend as much time as they like in the city, they do tend to get bored easily. Visiting each new landmark is fun, but walking between them takes time. The cows know the exact fun values Fi (1 ≤ Fi ≤ 1000) for each landmark i.
The cows also know about the cowpaths. Cowpath i connects landmark L1i to L2i (in the direction L1i -> L2i ) and requires time Ti (1 ≤ Ti ≤ 1000) to traverse.
In order to have the best possible day off, the cows want to maximize the average fun value per unit time of their trip. Of course, the landmarks are only fun the first time they are visited; the cows may pass through the landmark more than once, but they do not perceive its fun value again. Furthermore, Farmer John is making the cows visit at least two landmarks, so that they get some exercise during their day off.
Help the cows find the maximum fun value per unit time that they can achieve.
Input
- Line 1: Two space-separated integers: L and P
- Lines 2…L+1: Line i+1 contains a single one integer: Fi
- Lines L+2…L+P+1: Line L+i+1 describes cow path i with three space-separated integers: L1i , L2i , and Ti
Output
- Line 1: A single number given to two decimal places (do not perform explicit rounding), the maximum possible average fun per unit time, or 0 if the cows cannot plan any trip at all in accordance with the above rules.
Sample Input
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2
Sample Output
6.00
题目大意:
有一张图,图中有n个点,m条边。图中可能有环;让我们找到一个环,这个环的所有点权之和 / 所有边权之和 最大的那个环;最后输出这个除法的结果。
解题思路:
首先设一个环中点权之和为x, 边权之和为y, 那么设 mid * y - x < 0 那么 x / y > mid,所以这个mid对于这个x,y来说并不是答案,真正大答案要大于mid,如果mid * y - x > 0,说明mid > 答案,所以这个mid是由单调性的,根据这个性质我们可以推广到所有的点,我们的目的就是要找到一个最大的mid使得图中所有的 mid * y - x >= 0, 并且存在 mid * y - x == 0。 这样的话我们就可以把点权放到边上,假如有一条边为a -> b, 那么w[a->b] = mid * w[a->b] - node[a]; 即 mid * 原来的边权 - 出点的点权;最后我们在l,r这个范围进行二分去找答案就可以了,每次判断的条件是 只要图中存在负环,就让 l = mid, 否则让 r = mid;最后输出l;
注意点:
1.我们在实现的时候可以不断地重新建立新的图,也可以直接在原图上进行比较。我采用的是第二种方法,具体看代码;
2.eps = 1e-4;
3.注意数据的类型,以及输入
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1005, M = 5005;
const double eps = 1e-4;
int n, m;
int node[N];
double l, r;
int h[N], e[M], w[M], ne[M], idx;
inline void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
bool vis[N];
double d[N];
int cnt[N];
inline bool spfa(double mid) {
for(int i = 1; i <= n; i ++) {
cnt[i] = 0;
d[i] = 0;
vis[i] =false;
}
queue<int> q;
while(q.size()) q.pop();
for(int i = 1; i <= n; i ++) {
q.push(i);
vis[i] = true;
}
while(q.size()) {
int u = q.front(); q.pop();
vis[u] = false;
for(int i = h[u]; i + 1; i = ne[i]) {
int v = e[i];
if(d[v] > d[u] + mid * w[i] - node[u]) {
d[v] = d[u] + mid * w[i] - node[u];
cnt[v] = cnt[u] + 1;
if(cnt[v] >= n) return true;
if(!vis[v]) q.push(v), vis[v] = true;
}
}
}
return false;
}
inline void find(void) {
while(r - l > eps) {
double mid = (l + r) / 2;
if(spfa(mid)) l = mid;
else r = mid;
}
}
int main(void) {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i ++)
scanf("%d", &node[i]), r += node[i];
for(int i = 1; i <= m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
l = 1;
find();
printf("%.2lf\n", l);
return 0;
}