• 递归型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
    ",l);
    63     return 0;
    64 }
    View Code

    By:AlenaNuna

  • 相关阅读:
    integer to roman
    String to Integer (atoi)
    zigzag conversion
    Longest Palindromic Substring(最长回文子串)
    Longest Substring Without Repeating Characters
    letter combinations of a phone number(回溯)
    remove Nth Node from linked list从链表中删除倒数第n个元素
    generate parentheses(生成括号)
    排序算法入门之堆排序(Java实现)
    Integer 和int 比较
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/11797943.html
Copyright © 2020-2023  润新知