题目大意
题目大意:一个有向无环图(DAG),边权均为正整数。
定义一条路径的密度为 路径上的边权和/边数。
先有q组询问,每次给出xy,求从x到y的若干条路径中的最小路径密度是多少。
题目分析
令c为边权,d为路径条数
那么所求即为: ∑ c d \frac{\sum{c}}{d} d∑c
这是一个和式分式,对于这种题目,我们通常用一种方法叫做 01分数规划
我们二分答案,然后判断。
判断过程:把每条边边权-二分答案然后判断最短路的正负性。
如果最短路是负的那么答案不合法,修改r
否则修改l
代码
下附AC代码
#include<bits/stdc++.h>
using namespace std;
int read(){
char s;
int x=0,f=1;
s=getchar();
while(s<'0'||s>'9'){
if(s=='-')f=-1;
s=getchar();
}
while(s>='0'&&s<='9'){
x*=10;
x+=s-'0';
s=getchar();
}
return x*f;
}
const int N=55;
int n,m;
vector<int>v[N];
vector<double>v1[N];
double ans[N][N];
double dist[N];
bool in[N];
queue<int>q;
bool spfa(int s,int ask,double limit){
for(int i=1;i<=n;i++){
dist[i]=0x3f3f3f3f;
in[i]=0;
}
dist[s]=0;
q.push(s);
in[s]=1;
while(!q.empty()){
int x=q.front();
in[x]=0;
q.pop();
for(int i=0;i<v[x].size();i++){
int k=v[x][i];
if(dist[k]>dist[x]+v1[x][i]-limit){
dist[k]=dist[x]+v1[x][i]-limit;
if(!in[k]){
in[k]=1;
q.push(k);
}
}
}
}
return dist[ask]>0;
}
double maxn;
void go(int x,int y){
double l=0,r=maxn;
spfa(x,y,0);
if(dist[y]==0x3f3f3f3f){
ans[x][y]=-1;
return;
}
while(r-l>1e-6){
double mid=(l+r)/2;
if(spfa(x,y,mid))l=mid;
else r=mid;
}
ans[x][y]=l;
return;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int a,b,c;
a=read(),b=read(),c=read();
maxn+=c;
v[a].push_back(b);
v1[a].push_back(c);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
go(i,j);
}
}
int Q=read();
for(int i=1;i<=Q;i++){
int x=read(),y=read();
if(ans[x][y]<0)printf("OMG!\n");
else printf("%.3lf\n",ans[x][y]);
}
}