• UVA 11090 判负圈问题


    题目链接http://vjudge.net/problem/viewProblem.action?id=34650

    题目大意:

    给定n个点m条边的加权有向图,求平均权值最小的回路。
    平均权值=路径权值之和/路径边数

    我们可以通过找到他其中的最小和最大值,然后通过二分不断查找满足的点,然后尽可能的取到它的最大值,因为这里保留两位有效小数,所以设立

    while(la-st>0.001)即可

    找到一个满足的值是要建立在图上的每一条线段减去这个值后便能得到一个负圈,我们通常用spfa判负圈。

    这个spfa只是用来作判断并不是算最短路径,为了防止出现多个连通分量,你只从一个点开始可能遍历整个图,所以最开始就把节点全放入队列中,dp[i]的

    值全设定为0,如果出现负圈,则会为了找到最小值一直循环更新,我们用cnt[]数组,当某个点被访问了n次以上时,说明出现了负圈。

    具体spfa函数如下所示:

    bool spfa()
    {
        for(int i=1;i<=n;i++) cnt[i]=0,visit[i]=0;
        visit[1]=1;
        queue<int> q;
        for(int i=1;i<=n;i++) q.push(i),dp[i]=0;
        while(!q.empty()){
            int u=q.front();
            visit[u]=0;
            q.pop();
            for(int i=first[u];i!=-1;i=path[i].next){
                if(dp[path[i].y]>dp[u]+path[i].d){
                    dp[path[i].y]=dp[u]+path[i].d;
                    if(!visit[path[i].y]) {
                        q.push(path[i].y);
                        if(++cnt[path[i].y]>n) return true;
                    }
                }
            }
        }
        return false;
    }


    我们每次减去一个要找到的mid值,那我们一定要在判断结束后给它加回来以免下次判断出意外

    总代码如下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <queue>
     4 #include <algorithm>
     5 using namespace std;
     6 #define N 52
     7 int first[N],visit[N],k,cnt[N],n;
     8 double dp[N],maxn,minn;
     9 struct Path{
    10     int y,next;
    11     double d;
    12 }path[100010];
    13 
    14 void add(int a,int b,double c)
    15 {
    16     path[k].y=b,path[k].d=c,path[k].next=first[a];
    17     first[a]=k++;
    18 }
    19 
    20 bool spfa()
    21 {
    22     for(int i=1;i<=n;i++) cnt[i]=0,visit[i]=0;
    23     visit[1]=1;
    24     queue<int> q;
    25     for(int i=1;i<=n;i++) q.push(i),dp[i]=0;
    26     while(!q.empty()){
    27         int u=q.front();
    28         visit[u]=0;
    29         q.pop();
    30         for(int i=first[u];i!=-1;i=path[i].next){
    31             if(dp[path[i].y]>dp[u]+path[i].d){
    32                 dp[path[i].y]=dp[u]+path[i].d;
    33                 if(!visit[path[i].y]) {
    34                     q.push(path[i].y);
    35                     if(++cnt[path[i].y]>n) return true;
    36                 }
    37             }
    38         }
    39     }
    40     return false;
    41 }
    42 
    43 bool findMid(double mid)
    44 {
    45     for(int i=0;i<k;i++) path[i].d-=mid;
    46     bool temp=spfa();
    47     for(int i=0;i<k;i++) path[i].d+=mid;
    48     return temp;
    49 }
    50 
    51 int main()
    52 {
    53     int T,m,a,b;
    54     double c,st,la,mid,ans=-1;
    55     scanf("%d",&T);
    56     for(int j=1;j<=T;j++){
    57         memset(first,-1,sizeof(first));
    58         scanf("%d%d",&n,&m);
    59         k=0;
    60         maxn=0,minn=10000005;
    61         for(int i=0;i<m;i++)
    62         {
    63             scanf("%d%d%lf",&a,&b,&c);
    64             add(a,b,c);
    65             maxn=max(maxn,c);
    66             minn=min(minn,c);
    67         }
    68         st=minn-1,la=maxn;
    69         printf("Case #%d: ",j);
    70         if(!findMid(la+1)){printf("No cycle found.
    ");continue;}
    71         while(la-st>0.001){
    72             mid=st+(la-st)/2;
    73             if(findMid(mid)) la=mid;
    74             else ans=mid,st=mid;
    75         }
    76         printf("%.2f
    ",ans);
    77     }
    78     return 0;
    79 }
    View Code
  • 相关阅读:
    ReactiveCocoa RACObserve subscribeNext 时,只有值不一样时才响应
    ReactiveCocoa 监听Enabled和添加Command出错的处理方法
    Masonry + UIView Animations 注意事项
    addObserver forKeyPath options 注意事项
    ios中tabbar得title和navigationbar的title如何修改
    tableview 分组显示返回footerviewt和headerView的高度不能为0的问题
    UITableViewCell的选中时的颜色设置
    ios 枚举 位移操作
    设置UIButton 字体 颜色
    jsoup 源码分析
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3885508.html
Copyright © 2020-2023  润新知