[模板题] 最小密度路径

题目描述

这次的任务很简单,给出了一张有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
#include
#include
#include
#include
#include
#include
#include
#include
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;
}



你可能感兴趣的:(最短路径,动规Dp)