1. 程式人生 > 其它 >1720:均值最小環

1720:均值最小環

1720:均值最小環


時間限制: 1000 ms 記憶體限制: 131072 KB
提交數: 310 通過數: 62

【題目描述】

畫一個 n 個節點,m 條邊的帶權有向圖,想從中找出權值的平均值最小的環。有向圖中可能不存在環,求最小的平均權值。

【輸入】

共 m+1 行。

第$1行,2個整數n和m,表示點數和邊數。

第$2 ~ m+1行,每行3個正整數 $u,v,w,表示u與v之間有一條權值為w的有向邊。

【輸出】

如果輸入資料無環,輸出“PaPaFish is laying egg!”。(不含引號)

否則輸出一個浮點數 ans,表示所有環中,權值的平均值最小的環的平均權值。答案保留2位小數。

【輸入樣例】

2 2

1 2 2

2 1 3

【輸出樣例】

2.50

【提示】

【資料規模】

對於前40%的資料 n≤50,m≤5000;

對於100%的資料 $≤n≤1000,1≤m≤10000,0≤w≤10000000

二分答案,dfs判環

```

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int N = 1e5 + 10;
int n, m;
int h[N],ne[N],e[N];
double w[N];
double dis[N];
int idx;
bool st[N];
void add(int a,int b,double c)
{
e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}
bool bj;
double mid;
bool spfa(int t)
{
st[t] = 1;
for(int i = h[t]; ~i ; i = ne[i])
{
int j = e[i];
if(dis[j] <= dis[t] + w[i] - mid) continue;
if(st[j] && dis[t] + w[i] - mid <= 0) return 1;
dis[j] = dis[t] + w[i] - mid;
if(!st[j] && spfa(j)) return 1;
}
st[t] = 0;
return 0;
}

bool check(double k)
{
memset(st,0,sizeof(st));
memset(dis,0,sizeof(dis));
for(int i = 1;i <= n; i++)
{
if(!dis[i] && spfa(i)) return 1;
}
return 0;
}

int main()
{
scanf("%d %d",&n,&m);
memset(h, -1,sizeof(h));
double L = 0, R = 10000000 + 120;
double ans = -1;
double eps = 1e-3;
for(int i = 1; i <= m; i++)
{
int a, b;
double c;
scanf("%d %d %lf",&a,&b,&c);
add(a, b, c);
}
while(R - L >= 0.0004)
{
mid = (R + L) / 2;
if(check(mid))
{
R = mid;
ans = mid;
}
else L = mid;
}
if(ans != -1)
printf("%.2lf",ans);
else puts("PaPaFish is laying egg!");
return 0;
}

```