Codevs1183 泥泞的道路

  • 题目大意:给定一张图,每条边上都有一个长度和时间,求从1到n经过的路径中∑length/∑time的最大值。

  • 思路:二分答案+SPFA。假如有一解 length/timeans 更优,其中ans为已经得到的一个解,则有 lengthanstime0 ,即 lengthianstimei0 ,这样就转换为了,如果一个答案更优,那么对于各个边权为 lengthianstimei 的图,其到达点n最长路不小于0。当该值从正实数方向逼近0时,答案会越来越优。这时只需二分答案检验其合理性就可以了。需要说明的一点是,如果新建图中存在正环,那么这个情况是可行的,因为这样可以无限在环上跑以使到n的权值不小于0。

  • 代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=105;
int n;
double ans;
int p[maxn][maxn],t[maxn][maxn];
double a[maxn][maxn];

void init()
{
     scanf("%d",&n);
     for (int i=1;i<=n;++i)
       for (int j=1;j<=n;++j)
         scanf("%d",&p[i][j]);
     for (int i=1;i<=n;++i)
       for (int j=1;j<=n;++j)
         scanf("%d",&t[i][j]);
}

queue<int> q;
bool vis[maxn];
double dis[maxn];
int id[maxn];

bool spfa()
{
     for (int i=1;i<=n;++i)
       for (int j=1;j<=n;++j)
         a[i][j]=(double)p[i][j]-(double)t[i][j]*ans;
     memset(vis,0,sizeof(vis));
     memset(id,0,sizeof(id));
     memset(dis,-0x3f,sizeof(dis));
     while (!q.empty())
        q.pop();
     q.push(1);
     id[1]++;
     vis[1]=1;
     dis[1]=0.0;
     while (!q.empty())
     {
           int h=q.front();
           q.pop();
           vis[h]=0;
           for (int i=1;i<=n;++i)
           {
               if (i==h)
                 continue;
               if (dis[i]<dis[h]+a[h][i])
               {
                   dis[i]=dis[h]+a[h][i];
                   if (!vis[i])
                   {
                       vis[i]=1;
                       id[i]++;
                       if (id[i]>n)
                         return true;
                       q.push(i);
                   }
               }
           }
     }
     if (dis[n]>=0)
       return true;
     else 
       return false;
}

int main()
{
    init();
    double l=0.0,r=10.0;
    while (r-l>0.0001)
    {
          ans=(l+r)/2;
          if (spfa())
            l=ans;
          else
            r=ans;
    }
    printf("%.3f",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值