最短路径:信息学奥赛:1344:【例4-4】最小花费

信息学奥赛:1344:【例4-4】最小花费

参考文章

思路:
一开始我按照最短路径的方法去解这题,认为只要找到了从一条从原点到终点的最短一条路线,比如这条最短的路线从起点到终点每条线上的权值为:x1,x2,x3,x4;那么最后的答案就是
在这里插入图片描述

// 1344:【例4-4】最小花费
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXZ = 101;
const int maxn = 2005;
int map[maxn][maxn], dist[maxn], p[maxn], n, m, start, en;
bool flag[maxn];
double fare = 100;

void dijkstra(int start, int en){
	// 初始化
	for(int i = 1; i <= n; i++){
		dist[i] = map[start][i];
		flag[i] = false;
		if(dist[i] == MAXZ)
			p[i] = -1;
		else
			p[i] = start;
	} 
	dist[start] = 0;
	flag[start] = true;
	
	
	for(int i = 1; i <= n; i++){
		int temp = MAXZ, node = start;
		for(int j = 1; j <= n; j++){
			if(!flag[j] && dist[j] < temp){
				temp = dist[j];
				node = j;
			}
		}
		
		if(node == start)
			return;
		
		flag[node] = true;
		
		for(int j = 1; j <= n; j++)
			if(!flag[j] && map[node][j] < MAXZ){
				if(dist[node] + map[node][j] < dist[j]){
					dist[j] = dist[node] + map[node][j];
					p[j] = node;
				}
			}
	}
}

double f(int x){
	if(p[x] == -1)
		return 1.0;
	//cout << x << ' ' << map[p[x]][x] << endl;
	return (1.0 - (double)map[p[x]][x] / 100) * f(p[x]);
}


int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			map[i][j] = MAXZ;
	
	int x, y, z;
	for(int i = 1; i <= m; i++){
		cin >> x >> y >> z;
		map[x][y] = map[y][x] = z;
	}
	
	cin >> start >> en;
	dijkstra(start, en);
	
	double rate = f(en);
	//cout << rate << endl;
	
	printf("%.8lf", fare / rate);
	/*
	cout << endl;
	for(int i = 1; i <= n; i++)
		cout << p[i] << ' ';
	*/	
		
	return 0;
} 

然而结果却是这个鬼样子:
在这里插入图片描述
为什么会这样:我犯了一个很严重的错误:误以为当x1+x2+x3+x4最小时,那么
在这里插入图片描述
这个结果也一定最小。

看一个例子:
在这里插入图片描述
如果按照我上面的想法,那么走的路线就是1->2->5.看一下最终结果
在这里插入图片描述

换一条路线1->3->5,看一下最终结果
在这里插入图片描述
可见,后者比前者小。
关于(1-x1)(1-x2)…(1-xn)的最大值条件是不是等价于在x1+x2+…+xn的最小值这个问题,我是没有答案的,(毕竟我的数学忽悠小学生还可以)。如果想要下面这个公式的值最小,那么分母应该的乘积应该是最大。而不是x1+x2+x3+x4最小。
在这里插入图片描述

所以这题:还是我参考的文章那种解法:用求最短路径的方法求最大路径。
写完以后大概是这个鬼样子:

// 1344:【例4-4】最小花费
#include<iostream>
#include<cstdio>
using namespace std;
const int MINZ = 0;
const int maxn = 2005;
int n, m, start, en;
bool flag[maxn];
double dist[maxn], map[maxn][maxn], fare = 100;

void dijkstra(int start, int en){
	// 初始化
	for(int i = 1; i <= n; i++){
		dist[i] = map[start][i];
		flag[i] = false;
	} 
	dist[start] = 0;
	flag[start] = true;
	
	
	for(int i = 1; i <= n; i++){
		double temp = MINZ;
		int node = en;
		for(int j = 1; j <= n; j++){
			if(!flag[j] && dist[j] > temp){
				temp = dist[j];
				node = j;
			}
		}
		
		if(node == en)
			return;
		
		flag[node] = true;
		
		for(int j = 1; j <= n; j++)
			if(!flag[j] && map[node][j] > MINZ){
				if(dist[node] * map[node][j] > dist[j])
					dist[j] = dist[node] * map[node][j];
			}
	}
}

int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			map[i][j] = MINZ;
	
	int x, y, z;
	for(int i = 1; i <= m; i++){
		cin >> x >> y >> z;
		map[x][y] = map[y][x] = (double)(100 - z) / 100;
	}
	
	cin >> start >> en;
	dijkstra(start, en);
	
	printf("%.8lf", fare / dist[en]);
	return 0;
}

在这里插入图片描述

做完这题后,发现最短路径的权值不仅可以相加,还可以相乘,不仅可以求最短路径还可以求最大路径。

猜你喜欢

转载自blog.csdn.net/qq_43833364/article/details/105916042