题意:
给定n个点,每个点有一个开心度F[i],每个点有m条单向边,每条边有一个长度d,要求一个环,使得它的 开心度的和/长度和 这个比值最大。
n<=1000,m<=5000
题解:
最优比率环,很像以前做过的一题最优比率生成树。
首先二分一个答案r=sigma(xi*fi)/sigma(xi*di),设z=r*sigma(xi*di)-sigma(xi*fi),若能找到一个环满足z<=0,则代表sigma(xi*fi)>=r*sigma(xi*di),则r可以比当前的r要大,则l=mid;否则r=mid;
判断能否有一个环满足让z<=0,我们就让所有的边权=r*di-f[a[i].x],然后用spfa判负环即可。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 #include<queue>
7 #include<vector>
8 #include<cmath>
9 using namespace std;
10
11 const int N=1100,M=5100;
12 const double INF=(double)1e9;
13 int n,m,len,first[N],cnt[N];
14 double dis[N],F[N];
15 bool in[N];
16 struct node{
17 int x,y,next;
18 double d,w;
19 }a[2*M];
20 queue<int> q;
21
22 double mid;
23
24 double myabs(double x){return x>0 ? x:-x;}
25
26 void ins(int x,int y,double d)
27 {
28 a[++len].x=x;a[len].y=y;a[len].d=d;
29 a[len].next=first[x];first[x]=len;
30 }
31
32 double spfa(int st)
33 {
34 while(!q.empty()) q.pop();
35 for(int i=1;i<=n;i++) dis[i]=INF;
36 memset(cnt,0,sizeof(cnt));
37 memset(in,0,sizeof(in));
38 q.push(st);dis[st]=0;in[st]=1;
39 while(!q.empty())
40 {
41 int x=q.front();in[x]=0;cnt[x]++;q.pop();
42 if(cnt[x]==n) return 1;
43 for(int i=first[x];i;i=a[i].next)
44 {
45 int y=a[i].y;
46 if(dis[y]>=dis[x]+a[i].w)
47 {
48 dis[y]=dis[x]+a[i].w;
49 if(!in[y]) in[y]=1,q.push(y);
50 }
51 }
52 }
53 return 0;
54 }
55
56 bool check(double r)
57 {
58 for(int i=1;i<=len;i++) a[i].w=r*a[i].d-F[a[i].x];
59 return spfa(1);
60 }
61
62 int main()
63 {
64 freopen("a.in","r",stdin);
65 scanf("%d%d",&n,&m);
66 len=0;
67 memset(first,0,sizeof(first));
68 double l=0,r=0;
69 for(int i=1;i<=n;i++)
70 {
71 scanf("%lf",&F[i]);
72 r+=F[i];
73 }
74 for(int i=1;i<=m;i++)
75 {
76 int x,y;double d;
77 scanf("%d%d%lf",&x,&y,&d);
78 ins(x,y,d);
79 }
80 while(l<r)
81 {
82 mid=(l+r)/2;
83 if(check(mid)) l=mid;
84 else r=mid;
85 if(myabs(l-r)<=0.0000001) break;
86 }
87 mid=6.0;
88 if(myabs(l)<=0.0000001) printf("0
");
89 else printf("%.2lf
",l);
90 return 0;
91 }