题目大意:求最大,使得当
个
能兑换成
个
时,不存在无限兑换的情况。
根据题意建图,由等式*
=
*
,对
到
连接一条权值为
的边,当图中存在环时,如果环上所有权值乘积大于1,则
不成立。考虑到当
越大时,环上所有权值乘积一定会越大,即
具有单调性,所以在确定
的值时使用二分答案。
而当我们计算环上所有权值乘积时,容易出现精度问题,两边取对数得:
,即
,两边取负
,所以问题转换为判断图上是否有负权环,叠spfa做二分答案的判断条件即可。
也许是我才疏学浅,但这题出得让我叹为观止,真的太妙了!
#include "stdio.h"
#include "queue"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "iostream"
#include "algorithm"
using namespace std;
const int N=1005,M=2005;
int n,m;
int Head[N],Next[M],adj[M],tot;
double W[M];
void add(int u,int v,double w)
{
Next[++tot]=Head[u];
Head[u]=tot;
adj[tot]=v;
W[tot]=w;
}
double dis[N];
bool vis[N];
int cnt[N];
bool spfa(double w)
{
queue<int>q;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
q.push(i),vis[1]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int e=Head[u];e;e=Next[e])
{
int v=adj[e];
if(dis[v]>dis[u]+W[e]+w)
{
dis[v]=dis[u]+W[e]+w;
cnt[v]++;
if(cnt[v]>n) return false;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
return true;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
add(b,d,-log(c*1.0/a));
}
double l=0.0,r=1.0;
while(r-l>=1e-8)
{
double w=(l+r)/2.0;
if(spfa(-log(w))) l=w;
else r=w;
}
cout<<l<<endl;
return 0;
}
需要注意的是,不保证图联通,所以spfa时要先把所有点都加入队列中。