然后这个题是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; }