https://ac.nowcoder.com/acm/contest/33187/D
建边 /((b,d,c/a)/),那么会无限就说明有一个环边积大于 0 的环。
化积为和,对于边权都取 /(/log_2/),那么二分 /(w/),将每条边的边权变为 /(e[i].w-w/),那么变为是否有一个环边和大于 0,考虑并不是很好做,于是对于所有边都取相反数,那么就是是否有一个环和小于 0,即负环。建虚点,连每个点跑 spfa,即可。刚刚复习了下才学到可以判经过的路径长度是否大于 /(n/) 的厉害负环判法。
精度好像没咋卡我。
#include <bits/stdc++.h>
#define pb push_back
#define db double
using namespace std;
int rd() {
int sum=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {
if(ch=='-') f=-1; ch=getchar();
}
while(ch<='9'&&ch>='0') {
sum=sum*10+ch-'0'; ch=getchar();
}
return sum*f;
}
const int N=2005;
const db eps=1e-8;
struct edge {
int nex,to; db w;
}e[N];
int hea[N],cnt;
int n,m;
void add_edge(int x,int y,db z) {
e[++cnt].nex=hea[x]; e[cnt].to=y; e[cnt].w=z; hea[x]=cnt;
}
db dis[N];
int ct[N];
bool vis[N];
queue<int>q;
bool check(db W) {
// e[i].w=-(e[i].w-w)
W=log2(W);
for(int i=0;i<=n;i++) dis[i]=0.0,ct[i]=0,vis[i]=0;
for(int i=1;i<=n;i++) {
vis[i]=1; q.push(i);
}
while(!q.empty()) {
int x=q.front(); q.pop();
vis[x]=0;
// cout<<x<<" "<<dis[x]<<'/n';
for(int i=hea[x];i;i=e[i].nex) {
int y=e[i].to; db w=-(e[i].w+W);
// cout<<x<<" "<<y<<" "<<w<<'/n';
if(dis[y]>dis[x]+w) {
// cout<<x<<" "<<y<<" "<<w<<'/n';
dis[y]=dis[x]+w;
ct[y]=ct[x]+1;
if(ct[y]>=n) {
return 0;
}
if(!vis[y]) vis[y]=1,q.push(y);
}
// else if(abs(dis[x]+w-dis[y])<eps&&y==s) {
// cout<<"asdf";
// return 0;
// }
}
}
return 1;
}
signed main() {
n=rd(); m=rd();
for(int i=1;i<=m;i++) {
int a=rd(),b=rd(),c=rd(),d=rd();
// c/a
db qwq=log2(c)-log2(a);
// cout
// cout<<qwq<<'/n';
add_edge(b,d,qwq);
}
db l=0.0,r=1.0;
while(r-l>eps) {
db mid=(l+r)/2.0;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l;
return 0;
}
原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/276528.html