P2384 最短路(落谷)

题目背景

狗哥做烂了最短路,突然机智的考了Bosh一道,没想到把Bosh考住了…你能帮Bosh解决吗?

他会给你100000000000000000000000000000000000%10金币w

题目描述

给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径。

输入输出格式

输入格式:

 

第一行读入两个整数n,m,表示共n个点m条边。 接下来m行,每行三个正整数x,y,z,表示点x到点y有一条边权为z的边。

 

输出格式:

 

输出仅包括一行,记为所求路径的边权之积,由于答案可能很大,因此狗哥仁慈地让你输出它模9987的余数即可。

废话当然是一个数了w

//谢fyszzhouzj指正w

对于20%的数据,n<=10。

对于100%的数据,n<=1000,m<=1000000。边权不超过10000。

 

输入输出样例

输入样例#1: 复制

3 3
1 2 3 
2 3 3 
1 3 10

输出样例#1: 复制

9

说明

好好看一看再写哟w

虽然这个题是让求得个边乘积的最小值,实质上可以通过logMN=logM+logN转化为最短路径(将各边的权值转化为log下的值,然后通过Dijkstra找到最短的路径使logM+logN最小,也就是logMN最小,也就是MN的乘积最小)。

下面是代码:

#include<iostream>
#include<queue>
#include<vector>
#include<math.h>
using namespace std;

const int N = 1005;
int pre[N];
int bian[1001][1001];
int INF = 10005;
double dis[N];
const int mod = 9987;
struct Edge {
	int e;
	double d;
	bool operator<(const Edge&ed)const{
		return ed.d < d;
	}
};
vector<Edge>ve[N];
void Dijkstra() {
	for (int i = 0; i < N; i++) {
		dis[i] = INF;
	}
	priority_queue<Edge> pq;
	Edge ed;
	ed.d = 0;
	ed.e = 1;
	pq.push(ed);
	dis[1] = 0;
	while (!pq.empty()) {
		Edge ed = pq.top();
		pq.pop();
		for (int i = 0; i < ve[ed.e].size(); i++) {
			Edge edge = ve[ed.e][i];
			if (dis[edge.e] > dis[ed.e] + edge.d) {
				dis[edge.e] = dis[ed.e] + edge.d;
				edge.d = dis[edge.e];
				pq.push(edge);
				pre[edge.e] = ed.e;
			}

		}
	}
}
int main()
{
	int n, m;
	cin >> n >> m;
	int s,e,dis;

	for (int i = 0; i < m; i++) {
		cin >> s >> e >> dis;
		Edge edge;
		edge.e = e;
		edge.d =log(dis);//将原始权值转化为log下对应的值存入结构数组
		ve[s].push_back(edge);
		bian[s][e] = dis;//另外开一个二维数组存储原来两个顶点之间最初的权值,以便最后找到最短路径后计算乘积
	}
	
	Dijkstra();
	pre[1] = 0;
	int sum = 1;
	do{
		if (n == 1)
			break;
		sum = (sum*(bian[pre[n]][n])) % mod;//用dijkstra里保存的最短路经的节点顺序计算最小乘积
		n = pre[n];
	} while (n);
	cout << sum << endl;
    return 0;
}

 

点赞