
然后这个题是01分数规划,然而我并miu看出来,然后看了两分钟,happy的写了个floyd,然后成功挂掉。
这个题然后其实是一个
设路程数组为dis,时间为tim。
设一个数组x,x[i] = 1表示第i条边在所选的路线中,x[i] = 0表示第i条边不在路线中,(所以,dis[i],tim[i],为定值,x[i]不是定值,x[i]会随着你跑spfa而变)
然后我们把式子列出来就是:
R=(∑i=1ndis[i]∗x[i]∑i=1ndis[i]∗x[i])/(∑i=1ntim[i]∗x[i]∑i=1ntim[i]∗x[i])
。。。。他不支持markdown。。。。。。



当f(L)==0时,(看上面)L就是我们要求的R,就是最优解。
当f(L)>0时:

那么什么时候f(L) > 0呢?
有两种情况:
1、dist[n] > 0:
上面已经说了,dist[n]就相当于L,所以dist[n] > 0时,L就大于0咯。
2、存在正环:
因为本题是跑最长路,如果你找到一个正环,在里面一直绕,当前的权值肯定是非常大的,dist[n]一定大于0。
然后L就二分答案求一下,注意精度。。。然后就没有然后了。。。。
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef double db;
const int maxn=20000;
const db inf=0x7ffffff;
struct Edge {
int f;
int to;
db d;
db tim;
int next;
} edge[maxn];
int head[maxn],time[maxn];
db dist[maxn];
bool vis[maxn];
int n;
db dis[150][150],tim[150][150];
int tot;
void add(int f,int t,db d,db tt) {
edge[++tot].to = t;
edge[tot].d = d;
edge[tot].tim = tt;
edge[tot].next = head[f];
head[f] = tot;
}
deque<int>q;
void clr() {
tot = 0;
while(!q.empty())
q.pop_front();
for(int i = 1; i <= n; i++)
dist[i] = -inf;
memset(vis,0,sizeof(vis));
memset(time,0,sizeof(time));
// printf("%lf
",dist[1]);
}
bool spfa(db mid) {
clr();
q.push_front(1);
dist[1] = 0.0;
while(!q.empty()) {
int x = q.front();
q.pop_front();
vis[x] = 0;
for(int i = head[x]; i; i = edge[i].next) {
Edge e = edge[i];
if(dist[e.to] < dist[x] + (e.d - mid * e.tim)) {
dist[e.to] = dist[x] + (e.d - mid * e.tim);
if(!vis[e.to]) {
vis[e.to] = true;
time[e.to]++;
if(time[e.to] > n) {
return true;
}
if(!q.empty() && dist[e.to] > dist[q.front()])
q.push_front(e.to);
else
q.push_back(e.to);
}
}
}
}
if(dist[n] > 0)
return true;
return false;
}
db div() {
db l = 0,r = 100000000;
db ans = 0;
int k = 0;
while(k <= 100) {
double mid = ((l + r) / (double)(2));
if(!spfa(mid))
r = mid;
else
l = mid,ans = max(ans,mid);
k ++;
// printf("l:%.1lf r:%.1lf
",l,r);
}
return ans;
}
int main() {
scanf("%d",&n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%lf",&dis[i][j]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%lf",&tim[i][j]);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i != j) {
add(i,j,dis[i][j],tim[i][j]);
}
}
}
printf("%.3f",div());
return 0;
}