试题描述
|
考虑带权的有向图 G=(V,E) 以及 w:E→R,每条边 e=(i,j)(i≠j,i∈V,j∈V)的权值定义为 w(i,j),令 n=∣V∣。c=(c1,c2,⋯,ck)(ci∈V)是 G 中的一个圈当且仅当 (ci,ci+1)(1≤i<k)都在 E 中,这时称 k 为圈 c 的长度。同时令 c(k+1)=c,并定义圈 c=(c1,c2,⋯,ck)的平均值为: 即 c 上所有边的权值的平均值。令 μ∗(c)=min{μ(c)}为 G 中所有圈 c 的平均值的最小值。现在的目标是:在给定了一个图 G=(V,E)以及 w:E→R之后,请求出 G 中所有圈 c 的平均值的最小值 μ∗(c)=min{μ(c)}。 |
输入
|
第一行包含两个正整数 n 和 m,并用一个空格隔开,其中 n=∣V∣,m=∣E∣,分别表示图中有 n 个顶点和 m 条边;
接下来 m 行,每行包含用空格隔开的三个数 i,j,w(i,j),表示有一条边 (i,j)且该边的权值为w(i,j)。 输入数据保证图 G=(V,E)连通,存在圈且有一个点能到达其他所有点。 |
输出
|
仅包含一个实数 μ∗=min{μ(c)},要求输出到小数点后 8 位。
|
输入示例
|
样例输入 1 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 3 样例输入 2 2 2 1 2 -2.9 2 1 -3.1 |
输出示例
|
样例输出 1 3.66666667 样例输出 2 -3.00000000 |
其他说明
|
数据范围与提示
对于 20% 的数据,1≤n≤100,1≤m≤1000; 对于 40%的数据,1≤n≤1000,1≤m≤5000; 对于 100% 的数据,1≤n≤3000,1≤m≤10^4,∣wi,j∣≤10^7。 输入保证 1≤i,j≤n。 |
第一眼是和WordStrings一个尿性,然而就是一样的
二分答案加上SPFA
就很奈斯,然而调的时候把二分写错了,被人打了好久QAQ
下面给出代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<queue> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } int n,m; int head[1000006],to[1000006],nxt[1000006]; double c[1000006],v[1000006]; int total=0; void add(int x,int y,double z){ total++; to[total]=y; v[total]=z; nxt[total]=head[x]; head[x]=total; return ; } int book[1000006]; double dis[1000006]; bool spfa_find_circle(int x,double h){//SPFA判环 book[x]=1; for(int e=head[x];e;e=nxt[e]){ if(dis[to[e]]>dis[x]+v[e]-h){//如果更优,就判断是否为环 if(book[to[e]]) return true; else{ dis[to[e]]=dis[x]+v[e]-h;//更新 if(spfa_find_circle(to[e],h)) return true; } } } book[x]=0; return false; } bool check(double x){ for(int i=1;i<=n;i++) dis[i]=book[i]=0; bool f=0; for(int i=1;i<=n;i++){//枚举起点 if(spfa_find_circle(i,x)){ f=1; break; } } return f; } int main() { n=rd(); m=rd(); double minn=999999999,maxn=-999999999; for(int i=1;i<=m;i++){ int x,y; double z; x=rd(); y=rd(); scanf("%lf",&z); add(x,y,z);//选出最大和最小值,开始的时候取得太大了,然后爆了,因为平均数肯定在最大和最小值之间 minn=min(minn,z); maxn=max(maxn,z); } double l=minn,r=maxn; while(r-l>1e-9){ double mid=(r+l)/2.0;//写成了(r-l)/2.0 QAQ if(check(mid)) r=mid; else l=mid; } printf("%.8lf",r); return 0; }