/* 和求最小生成树差不多 转载思路:http://www.cnblogs.com/wally/p/3228171.html 思路:之前做过最小比率生成树,也是属于0/1整数划分问题,这次碰到这道最优比率环,很是熟悉,可惜精度没控制好,要不就是wa,要不就是tle,郁闷啊!实在是懒得码字,直接copy吧: 题目的意思是:求一个环的{点权和}除以{边权和},使得那个环在所有环中{点权和}除以{边权和}最大。 令在一个环里,点权为v[i],对应的边权为e[i], 即要求:∑(i=1,n)v[i]/∑(i=1,n)e[i]最大的环(n为环的点数), 设题目答案为ans, 即对于所有的环都有 ∑(i=1,n)(v[i])/∑(i=1,n)(e[i])<=ans 变形得ans* ∑(i=1,n)(e[i])>=∑(i=1,n)(v[i]) 再得 ∑(i=1,n)(ans*e[i]-v[i]) >=0 稍分析一下,就有: 当k<ans时,就存在至少一个环∑(i=1,n)(k*e[i]-v[i])<0,即有负权回路(边权为k*e[i]-v[i]); 当k>=ans时,就对于所有的环∑(i=1,n)(k*e[i]-v[i])>=0,即没有负权回路。 然后我们就可以使新的边权为k*e[i]-v[i],用spfa来判断付权回路,二分ans。 */ #include<stdio.h> #include<string.h> #include<queue> #include<stdlib.h> using namespace std; #define N 1100 #define eps 1e-3 #define inf 0x3fffffff struct node { int u,v,w,next; }bian[N*5*2]; int head[N],yong,f[N],n; void init() { yong=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w) { bian[yong].u=u; bian[yong].v=v; bian[yong].w=w; bian[yong].next=head[u]; head[u]=yong++; } int spfa(double m) { queue<int>q; int vis[N],v,cou[N]; double dis[N]; int i; memset(vis,0,sizeof(vis)); memset(cou,0,sizeof(cou)); for(i=1;i<=n;i++) dis[i]=inf; dis[1]=0; cou[1]++; q.push(1); while(!q.empty()) { v=q.front(); q.pop(); vis[v]=0; for(i=head[v];i!=-1;i=bian[i].next) { int vv=bian[i].v; double tmp=m*bian[i].w-f[vv];//构造新边 if(dis[v]+tmp<dis[vv]){ dis[vv]=dis[v]+tmp; if(!vis[vv]) { vis[vv]=1; if(++cou[vv]>n)// return 1; q.push(vv); } } } } return 0; } int main(){ int m,i,a,b,c; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(i=1;i<=n;i++) scanf("%d",&f[i]); while(m--) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } double l=0.0,r=10000.0,ans=0,mid; while(r-l>eps) {//结束条件为l>r mid=(r+l)/2; if(spfa(mid)) { ans=mid; l=mid+0.00001; } else r=mid-0.00001; } printf("%.2f ",ans); } return 0; }