题目背景
狗哥做烂了最短路,突然机智的考了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;
}