最短路徑:信息學奧賽: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;
}

在這裏插入圖片描述

做完這題後,發現最短路徑的權值不僅可以相加,還可以相乘,不僅可以求最短路徑還可以求最大路徑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章