时空限制 1000ms / 128MB
题目描述
给出一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个节点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。
输入格式:
第一行包括2个整数N和M。
以下M行,每行三个数字A、B、W,表示从A到B有一条权值为W的有向边。
再下一行有一个整数Q。
以下Q行,每行一个询问X和Y,如题意所诉。
输出格式:
对于每个询问输出一行,表示该询问的最小密度路径的密度(保留3位小数),如果不存在这么一条路径输出“OMG!”(不含引号)。
说明
1 ≤ N ≤ 50,1 ≤ M ≤ 1000,1 ≤ W ≤ 100000,1 ≤ Q ≤ 100000
题目分析
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示从
i
i
i到
j
j
j经过
k
k
k条边的所有路径中的最小密度值
n范围很小,直接跑floyd即可
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
typedef long long lt;
typedef double dd;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const dd inf=1e9;
const int maxn=110;
int n,m,Q;
dd dp[maxn][maxn][maxn*10];
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=m;++k)
dp[i][j][k]=inf;
for(int i=1;i<=m;++i)
{
int u=read(),v=read(); dd dis;
scanf("%lf",&dis);
dp[u][v][1]=min(dp[u][v][1],dis);
}
for(int t=2;t<=m;++t)
for(int x=1;x<=n;++x)
for(int y=1;y<=n;++y)
for(int k=1;k<=n;++k)
dp[x][y][t]=min(dp[x][y][t],dp[x][k][t-1]+dp[k][y][1]);
Q=read();
while(Q--)
{
int s=read(),t=read();
dd ans=inf;
for(int i=1;i<=m;++i)
if(dp[s][t][i]!=inf) ans=min(ans,dp[s][t][i]/(dd)i);
if(ans==inf) printf("OMG!\n");
else printf("%.3lf\n",ans);
}
return 0;
}