D120 最短路→差分约束 SPFA 算法 P4926 [1007] 倍杀测量者

D120 最短路→差分约束 SPFA 算法 P4926 [1007] 倍杀测量者_哔哩哔哩_bilibili

 

P4926 [1007] 倍杀测量者 - 洛谷

若存在至少满足一个约束条件的解,输出最大的 T. 若不存在,输出 -1.

思路

注意本题与前面题的不同:前面题都是求 “满足所有约束条件的解”,本题是求 “存在至少满足一个约束条件的解”

设 $f[A]$ 表示选手 $A$ 得的分数

A 说 “我没 k 倍杀选手 B 就吃顿好的” ,变成约束条件:$f[A]\le f[B]*k$

A 说 “选手 B 把我 k 倍杀我就吃顿好的” ,变成约束条件:$f[A]*k\le f[B]$,即 $f[A]\le f[B]*\frac{1}{k}$

设定一个正常数 T 后,约束条件变为:

1. $f[A]\le f[B]*(k-T)$

2. $f[A]\le f[B]*\frac{1}{k+T}$

对于已知选手的得分 $f[A]=x$,变成约束条件:$f[A]\le x$ 且 $f[A]\ge x$

令 0 号点的得分为 $f[0]=1$,则 $f[A]\le f[0]*x$ 且 $f[A]\ge f[0]*x$

3. $f[A]\le f[0]*x$

4. $f[0]\le f[A]*\frac{1}{x}$

把变量 $f[i]$ 看做点,下标做为点的编号,连边建图,跑乘积最长路,如果存在环,则说明满足了一个约束条件

我们发现,$T$ 越小,$(k-T)$ 与 $\frac{1}{k+T}$ 越大,条件越容易成立,所以具有单调性,可以二分 $T$

相关板子:

D116【模板】最短路→差分约束 SPFA 算法 P5960 差分约束 - 董晓 - 博客园

 

// 差分约束 SPFA 算法 O(NM*log(10^7))
#include<bits/stdc++.h>
using namespace std;

const int N=1010,M=N*3;
int h[N],idx,ne[M],to[M]; double ww[M];
void add(int x,int y,double w){
  to[++idx]=y;ww[idx]=w;ne[idx]=h[x];h[x]=idx;
}
int n,s,t,x[N],cnt[N],vis[N];
struct F{int o,A,B,k;}f[N];
double d[N];

void build(double T){
  idx=0; memset(h,0,sizeof(h));
  for(int i=1;i<=s;i++){
    auto [o,A,B,k]=f[i];
    if(o==1) add(B,A,k-T);
    else add(B,A,1.0/(k+T));
  }  
  for(int i=1;i<=n;i++) if(x[i]){
    add(0,i,x[i]);
    add(i,0,1.0/x[i]);
  }
}
int spfa(double T){
  build(T); //建图
  queue<int> q;
  for(int i=0;i<=n;i++) d[i]=1,cnt[i]=0,q.push(i),vis[i]=1;    

  while(!q.empty()){
    int u=q.front(); q.pop();vis[u]=0;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i]; double w=ww[i];
      if(d[v]<d[u]*w){
        d[v]=d[u]*w; //乘积最长路
        cnt[v]=cnt[u]+1;
        if(cnt[v]>=n+1) return true; //有环
        if(!vis[v]) q.push(v),vis[v]=1;
      }
    }
  }
  return false; //无环
}
int main(){
  cin>>n>>s>>t;
  for(int i=1,o,A,B,k;i<=s;i++){
    cin>>o>>A>>B>>k;
    f[i]={o,A,B,k};
  }
  for(int i=1,C,x1;i<=t;i++) cin>>C>>x1,x[C]=x1;
  
  double l=0,r=10,mid;
  while(r-l>1e-6){
    mid=(l+r)/2;
    spfa(mid)?l=mid:r=mid;
  }
  if(l==0) puts("-1"); //找不到正T,无解
  else printf("%.6lf\n",l);
}

 

posted @ 2026-03-30 19:34  董晓  阅读(112)  评论(0)    收藏  举报