题目描述
这次的任务很简单,给出了一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个节点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。
输入格式
第一行包括2个整数N和M。
以下M行,每行三个数字A、B、W,表示从A到B有一条权值为W的有向边。
再下一行有一个整数Q。
以下Q行,每行一个询问X和Y,如题意所诉。
输出格式
对于每个询问输出一行,表示该询问的最小密度路径的密度(保留3位小数),如果不存在这么一条路径输出“OMG!”(不含引号)。
样例输入
3 3
1 3 5
2 1 6
2 3 6
2
1 3
2 3
样例输出
5.000 5.500
数据范围
对于60%的数据,有1 ≤ N ≤ 10,1 ≤ M ≤ 100,1 ≤ W ≤ 1000,1 ≤ Q ≤ 1000;
对于100%的数据,有1 ≤ N ≤ 50,1 ≤ M ≤ 1000,1 ≤ W ≤ 100000,1 ≤ Q ≤ 100000。
注意此题有重边。
题目分析
朴素的Floyd多源最短路暴力除法更新肯定是错的,可以轻松举出反例
这个时候只需要给Floyd加一维边数即可
动规方程:
f[i,j,t]=min{map[i,k,t-1]+map[k,j,1]);
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=55;
struct Floyd { //最小密度路径
int n;
double map[maxn][maxn][maxn];
double d[maxn][maxn]; //密度
void init(int n) {
this->n=n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
for(int k=1; k<=n; k++)
map[i][j][k]=1e10;
d[i][j]=1e10;
}
}
void AddEdge(int from,int to,double dist) {
map[from][to][1]=min(map[from][to][1],dist);
}
void main() {
for(int t=2; t<=n; t++) //经过的边
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
map[i][j][t]=min(map[i][j][t],map[i][k][t-1]+map[k][j][1]);
density();
}
void density() {
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=n; k++)
if(map[i][j][k]!=1e10)d[i][j]=min(d[i][j],map[i][j][k]/k);
}
} ;
Floyd floyd;
int n,m,q;
int main() {
n=Get_Int();
m=Get_Int();
floyd.init(n);
for(int i=1; i<=m; i++) {
int x=Get_Int(),y=Get_Int(),v=Get_Int();
floyd.AddEdge(x,y,v);
}
floyd.main();
q=Get_Int();
for(int i=1; i<=q; i++) {
int x=Get_Int(),y=Get_Int();
if(floyd.d[x][y]==1e10)puts("OMG!");
else printf("%0.3lf\n",floyd.d[x][y]);
}
return 0;
}
转载请注明原文地址: https://ju.6miu.com/read-968775.html