链接
https://www.luogu.com.cn/problem/P4926
题意
有两种约束条件
- s a ≥ s b ( k − T ) s_a\ge s_b(k-T) sa≥sb(k−T)
- s b < s a ( k + T ) s_b< s_a(k+T) sb<sa(k+T)
现在有 s s s 个条件, t t t 个已知点,使 T T T 尽可能大来满足所有条件
思路
- o = 1 o=1 o=1,
s a ≥ s b ( k − T ) → log ( s a ) ≥ log ( s b ) + log ( k − T ) s_a\ge s_b(k-T) \rightarrow \log(s_a)\ge \log(s_b)+\log(k-T) sa≥sb(k−T)→log(sa)≥log(sb)+log(k−T)
- o = 2 o=2 o=2,
s b < s a ( k + T ) → s a ≥ s b k + T → log ( s a ) ≥ log ( s b ) − log ( k + T ) s_b< s_a(k+T)\rightarrow s_a\ge \frac{s_b}{k+T}\rightarrow \log(s_a)\ge \log(s_b)-\log(k+T) sb<sa(k+T)→sa≥k+Tsb→log(sa)≥log(sb)−log(k+T)(误差不超过 1 0 − 4 10^{-4} 10−4,大于可近似成大于等于)
按照上述关系建立有向边
对于已知点 c c c:
- s c − 0 ≥ x s_c-0\ge x sc−0≥x
- 0 − s c ≥ − x 0-s_c\ge -x 0−sc≥−x
建立一个超级起点与已知点之间建立一条权值为 log ( x ) \log(x) log(x) 的有向边,再在已知点与超级起点建立一条权值为 − log ( x ) -\log(x) −log(x) 的有向边
最后在超级起点与所有点之间建立一条权值为 0 0 0 的有向边,使图连通
二分 T T T,跑最长路,有正环则无解
代码
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const int N=1e3+5;
int n,s,t;
int vis[N],cnt[N];
DB dist[N];
bool st[N];
struct E {
int v,o;
DB w;
E() {}
E(int v,DB w,int o):v(v),w(w),o(o) {}
};
vector<E> G[N];
bool spfa(DB mid) {
for(int i=1;i<=n;i++) {
cnt[i]=0;
st[i]=false;
dist[i]=-1e8;
}
queue<int> q;
q.push(n);
dist[n]=0;
cnt[n]=1;
st[n]=true;
while(q.size()) {
int u=q.front();
q.pop();
st[u]=false;
for(auto x:G[u]) {
int v=x.v;
DB w=x.w;
if(x.o==1) w=log(w-mid);
else if(x.o==2) w=-log(w+mid);
if(dist[v]<dist[u]+w) {
dist[v]=dist[u]+w;
cnt[v]++;
if(cnt[v]>=n) return true;
if(!st[v]) {
st[v]=true;
q.push(v);
}
}
}
}
return false;
}
int main() {
//freopen("D:/Sublime Text 3/in.txt","r",stdin);
scanf("%d%d%d",&n,&s,&t);
for(int i=1;i<=s;i++) {
int o,a,b;
DB k;
scanf("%d%d%d%lf",&o,&a,&b,&k);
if(o==1) G[b].PB(E(a,k,1));
else G[b].PB(E(a,k,2));
}
for(int i=1;i<=t;i++) {
int c;
DB x;
scanf("%d%lf",&c,&x);
G[n+1].PB(E(c,log(x),3));
G[c].PB(E(n+1,-log(x),3));
}
for(int i=1;i<=n;i++) G[n+1].PB(E(i,0,3));
n++;
DB l=0,r=10;
DB res=-1;
while(r-l>1e-6) {
DB mid=(l+r)/2;
if(spfa(mid)) res=mid,l=mid;
else r=mid;
}
if(res==-1) puts("-1");
else printf("%.10f\n",l);
return 0;
}