信息学奥赛: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;
}
做完这题后,发现最短路径的权值不仅可以相加,还可以相乘,不仅可以求最短路径还可以求最大路径。