loop|loop.in|loop.out
题目描述:
给出一个有向带权图,权为边权,求一个简单回路,使其平均边权最小。
简单回路指不多次经过同一个点的回路。
输入格式:
第一行两个整数,表示图的点数n和图的边数m。
接下来m行,每行三个整数a,b,c表示一条从a指向b权为c的有向边。
输出格式:
一行一个实数,表示最小平均边权,保留两位小数。
样例输入:
4 5
1 2 3
2 3 5
3 1 4
3 4 3
4 1 2
样例输出:
3.25
数据范围:
30% n<=10 ,m<=20
100% n<=600,m<=1000,0<=c<=32768
保证原图强连通,无自环
hja的优化方法:类似题目可以将浮点数乘10000转换为整数,但是有爆int的风险。
求负环用bellman-ford O(NV)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 660 #define MAXE 5000 #define PROB "loop" #define eps 1e-4 #define INF 0x3f3f3f3f3f3f3f3fLL #define inf 1E1000 #ifdef unix #define LL "%lld" #else #define LL "%I64d" #endif typedef long long qword; struct edge { int x,y; qword z; }el[MAXE]; qword dis[MAXN]; int main() { freopen(PROB".in","r",stdin); //freopen(PROB".out","w",stdout); int n,m; scanf("%d%d",&n,&m); int i,j,k,x,y; qword z; qword l,r,mid; l=r=0; for (i=0;i<m;i++) { scanf("%d%d"LL,&x,&y,&z); x--;y--; z*=10000; el[i].x=x; el[i].y=y; el[i].z=z; if(z<0)l+=z; else r+=z; } bool flag; while (l+1<r) { mid=(l+r)/2; for (i=0;i<=n;i++)dis[i]=INF; dis[0]=0; flag=false; for (i=0;i<m;i++) { el[i].z-=mid; } for (i=0;i<n;i++) { for(j=0;j<m;j++) { if (dis[el[j].x]+el[j].z<dis[el[j].y]) dis[el[j].y]=dis[el[j].x]+el[j].z; } } for (i=0;i<n;i++) { for(j=0;j<m;j++) { if (dis[el[j].x]+el[j].z<dis[el[j].y]) flag=true; if (flag)break; } if (flag)break; } for(i=0;i<m;i++)el[i].z+=mid; if (flag) { r=mid; }else { l=mid; } } printf("%.2lf ",(double)r/10000.0); }