首页 > 代码库 > 【poj3621】最优比率环

【poj3621】最优比率环

题意:

给定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\n");
89     else printf("%.2lf\n",l);
90     return 0;
91 }

 

【poj3621】最优比率环