题意:
给定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 }
时间: 2024-10-25 14:54:03