典型的求最优比例环问题
参考资料:
http://blog.csdn.net/hhaile/article/details/8883652
此题中,给出每个点和每条边的权值,求一个环使 ans=∑点权/∑边权 最大。
因为题目要求一个环,而且必然是首尾相接的一个我们理解的纯粹的环,不可能是其他样子的环,
所以我们可以把一条边和指向的点看做整体处理。
上面方程可以化为:ans×e[i]-p[i]=0
以它为边权二分答案,spfa求负环,有负环则该ans可行,增大下界。
若一直不可行,则无解。
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
#include<algorithm>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
#define N 1010
#define M 5010
struct node
{
int next,v,w;
}e[M];
int n,m,h,head[N],p[N],inq[N],outq[N];
double d[N];
void addedge(int a,int b,int c)
{
e[h].v=b;
e[h].w=c;
e[h].next=head[a];
head[a]=h++;
}
bool spfa(int s,double ans)
{
int i,cnt=0;
for(i=0;i<=n;i++)
d[i]=2000000000;
memset(inq,0,sizeof inq);
memset(outq,0,sizeof outq);
d[s]=0;
inq[s]=1;
queue<int> q;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
inq[x]=0;
outq[x]++;
cnt++;
if(outq[x]>n) return 0;
if(cnt>(n+m)<<1) return 0;
for(i=head[x];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(d[v]>d[x]+ans*e[i].w-p[v])
{
d[v]=d[x]+ans*e[i].w-p[v];
if(!inq[v])
q.push(v);
}
}
}
return 1;
}
int main()
{
int a,b,c,i;
double le,ri,mid;
while(~scanf("%d%d",&n,&m))
{
memset(head,-1,sizeof head);
h=0;
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
}
le=0;ri=1010;
double ans=0;
while(ri-le>1e-5)
{
mid=(le+ri)/2.0;
if(spfa(1,mid))
{
ri=mid;
}
else
{
ans=mid;
le=mid;
}
}
printf("%.2lf\n",ans);//G++要用%f才能A
}
return 0;
}