题目:
题意:
一张图,每一个点有价值,每一条边有花费,求一条起点终点相同的路径,满足价值/花费最大。其中点重复经过价值不变,边重复经过代价累加。
题解:
点重复价值不变的话显然是让我们找比率最大环,那么我们按照边权
costi−vali∗L
c
o
s
t
i
−
v
a
l
i
∗
L
连边,然后看看有没有正环,如果有的话说明可以更大
那么这个边的权值和点的怎么处理呢?可以把点的权值移到上一个边上,那么这样第一个点怎么办呢?因为我们要找的肯定是一个环,那么第一个点肯定被加到最后一条边上
一开始数组全开成整形差评
代码:
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int M=10005;
const int N=5005;
int tot,nxt[M],v[M],point[N],w[M],a[N],n,m,tim[N];bool vis[N],fff;
double c[M],dis[N];
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
bool check(double mid)
{
for (int i=1;i<=tot;i++) c[i]=a[v[i]]-mid*w[i];
queue<int>q;
for (int i=1;i<=n;i++) dis[i]=-1,q.push(i),vis[i]=1,tim[i]=1;
dis[1]=0;
while (!q.empty())
{
int now=q.front(); q.pop(); vis[now]=0;
for (int i=point[now];i;i=nxt[i])
if (dis[v[i]]<dis[now]+c[i])
{
dis[v[i]]=dis[now]+c[i];
if (!vis[v[i]])
{
q.push(v[i]),vis[v[i]]=1,tim[v[i]]++;
if (tim[v[i]]>n) return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=m;i++)
{
int x,y;scanf("%d%d%d",&x,&y,&w[i]);
addline(x,y);
}
double l=0,r=1e4;
while (r-l>=1e-6)
{
double mid=(l+r)/2;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.2lf",l);
}