其他分享
首页 > 其他分享> > 递归型SPFA判负环 + 最优比例环 || [Usaco2007 Dec]奶牛的旅行 || BZOJ 1690 || Luogu P2868

递归型SPFA判负环 + 最优比例环 || [Usaco2007 Dec]奶牛的旅行 || BZOJ 1690 || Luogu P2868

作者:互联网

题外话:最近差不多要退役,复赛打完就退役回去认真读文化课。

题面:P2868 [USACO07DEC]观光奶牛Sightseeing Cows

题解:最优比例环

题目实际是要求一个ans,使得对于图中任意一个环满足 sig(i=1,n)v[i]/sig(i=1,n)e[i]<=ans

所以将公式变换为:sig(i=1,n)v[i]-[(sig(i=1,n)v[i])*ans]<=0

sig(i=1,n)(v[i]-ans*e[i])<=0

最终化为:sig(i=1,n)(ans*e[i]-v[i])>=0,即以ans*e[i]-v[i]为新的边权重建图,对于图中任意一个环都能满足该条件的即为ans

所以二分答案,对于每个mid重建图,用递归型SPFA判断负环,若sig(i=1,n)(mid*e[i]-v[i])<0 则说明mid<ans,否则说明mid>=ans

代码:

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn=1050,maxm=5050,inf=(1<<30)-5;
 5 const double jd=1e-3;
 6 int N,M,num_edge=0,edge_head[maxn],u,v;
 7 double V[maxn],e,l,r,mid,Dis[maxn];
 8 bool vis[maxn],flag;
 9 struct Edge{ int to,nx;double e,dis; }edge[maxm];
10 inline void Add_edge(int from,int to,double e){
11     edge[++num_edge].nx=edge_head[from];
12     edge[num_edge].to=to;
13     edge[num_edge].e=e;
14     edge_head[from]=num_edge;
15     return;
16 }
17 inline void Rebuild(){
18     for(int i=1;i<=N;i++)
19         for(int j=edge_head[i];j;j=edge[j].nx)
20             edge[j].dis=edge[j].e*mid-V[edge[j].to];
21     return;
22 }
23 inline void SPFA(int x){
24     if(flag) return;
25     vis[x]=1;
26     for(int i=edge_head[x];i;i=edge[i].nx){
27         int y=edge[i].to;
28         if(Dis[y]>Dis[x]+edge[i].dis){
29             if(vis[y]){
30                 flag=1;
31                 return;
32             }
33             Dis[y]=Dis[x]+edge[i].dis;
34             SPFA(y);
35         }
36     }
37     vis[x]=0;
38 }
39 inline bool Check(){
40     for(int i=1;i<=N;i++) vis[i]=0,Dis[i]=0;
41     flag=0;
42     for(int i=1;i<=N;i++){
43         SPFA(i);
44         if(flag) break;
45     }
46     return flag;
47 }
48 int main(){
49     scanf("%d%d",&N,&M);
50     for(int i=1;i<=N;i++) scanf("%lf",&V[i]);
51     for(int i=1;i<=M;i++){
52         scanf("%d%d%lf",&u,&v,&e);
53         Add_edge(u,v,e);
54     }
55     l=0; r=10000;
56     while(l+jd<r){
57         mid=(l+r)/2;
58         Rebuild();
59         if(Check()) l=mid;
60         else r=mid;
61     }
62     printf("%.2lf\n",l);
63     return 0;
64 }
View Code

 


By:AlenaNuna

 

标签:vis,Luogu,dis,判负,SPFA,sig,ans,Dis,BZOJ
来源: https://www.cnblogs.com/AlenaNuna/p/11797943.html