codevs 1183 泥泞的道路 (二分+SPFA+差分约束)

/*
二分答案(注意精度)
对于每一个答案 有(s1+s2+s3...)/(t1+t2+t3...)>=ans 时符合条件
这时ans有变大的空间
对于上述不等式如果枚举每一条路显得太暴力
化简一下变成 :s1-t1*ans+s2-t2*ans+s3-t3*ans...>=0
差分约束跑最长路 如果dis[n]>0 或者有正环 (开始这个忘掉了)ans就合法 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
const double Jing=0.0001;
using namespace std;
double s[110][110],t[110][110],ans,a[110][110],dis[110];
int n,f[110],c[110],falg;
void SPFA(int st)
{
    memset(f,0,sizeof(f));
    memset(dis,-0x3f,sizeof(dis));
    queue<int>q;
    q.push(st);f[st]=1;dis[st]=0,c[st]=1;
    while(!q.empty())
      {
          int k=q.front();
          q.pop();
          if(c[k]>n)
          {
              falg=1;break;
          }
          for(int i=1;i<=n;i++)
            if(s[k][i]&&dis[i]<dis[k]+a[k][i])
              {
                dis[i]=dis[k]+a[k][i];
                if(f[i]==0)
                  {
                    c[i]=c[k]+1;
                  q.push(i);
                  f[i]=1;
                }
            }
        f[k]=0;
      }
}
bool check(double x)
{
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        a[i][j]=s[i][j]-x*t[i][j];
    falg=0;
    SPFA(1);
    if(dis[n]>0||falg==1)return 1;
    else return 0;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        cin>>s[i][j];
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        cin>>t[i][j];
    double l=0,r=100;
    while(r-l>Jing)
      {
          double mid=(l+r)/2;
          if(check(mid))
            {
                ans=mid;
                l=mid;
          }
        else r=mid;
      }
    printf("%.3f",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5540438.html