Description
泡泡鱼是一条调皮的鱼,ta的家住在一片珊瑚礁上。在ta的眼里,这些珊瑚礁的形态可以脑补成一个n个节点,m条边的带权图,在海水的腐蚀下,这些珊瑚礁形成了许多的环,ta想考考你能不能找出这些环中,权值的平均值最小的环。泡泡鱼这么聪明,ta当然知道答案,调皮的ta对你说,如果你算错了,就要吃ta下的蛋。因为ta很调皮,ta把图变成了有向图,还有可能用无环图坑你。为代表你知道,你只需告诉ta最小的平均权值即可。
Input
共m+1行。
第1行,2个整数n和m,表示珊瑚礁的点数和边数。
第2~m+1行,每行3个正整数u,v,w,表示u与v之间有一条权值为w的有向边。
Output
如果输入数据无环,输出”PaPaFish is laying egg!”。(不含引号)
否则输出一个浮点数ans, 表示所有环中,权值的平均值最小的环的平均权值。答案保留2位小数。
Sample Input
2 2
1 2 2
2 1 3
Sample Output
2.50
Data Constraint
对于前40%的数据n <= 50, m <= 5000
对于100%的数据1 <= n <= 1000, 1 <= m <= 10000, 0 <= w <= 10000000
Solution
二分答案,将边权减去答案,判负环
判负环有两种方法
一是直接用SPFA,当一个点的入队次数超过n次时就说明有负环
二是用dfs优化SPFA,标记数组记录点是否在栈中,当发现一个点的距离可以更新另一个点的距离,而被更新的点在栈中,则说明有负环
此题中第二种方法快
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 1010
#define db double
using namespace std;
int last[N],next[N*100],to[N*100],tot=0,bz[N],n,m,flag;
db ans=21474354354321578,date[N*100],num[N],avg,f[N];
void putin(int x,int y,db z)
{
next[++tot]=last[x];last[x]=tot;to[tot]=y;date[tot]=z;
}
void dg(int x)
{
bz[x]=1;
for(int i=last[x];i;i=next[i])
{
int y=to[i];
if(flag) return;
if(f[y]>f[x]+date[i]-avg)
{
f[y]=f[x]+date[i]-avg;
if(bz[y]) flag=1;
else dg(y);
}
}
bz[x]=0;
}
bool pd(db m)
{
memset(f,0,sizeof(f));
memset(bz,0,sizeof(bz));
flag=0;avg=m;
fo(i,1,n)
if(!bz[i])
{
dg(i);
if(flag) return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,m)
{
int x,y;db z;
scanf("%d %d %lf",&x,&y,&z);
putin(x,y,z);
}
db l=0,r=10000000;
while(l+0.00001<r)
{
db m=(l+r)/2;
if(pd(m)) r=m;else l=m;
}
if(r>=9999999) printf("PaPaFish is laying egg!\n");
else printf("%.2lf\n",l);
}