信息學奧賽: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;
}
做完這題後,發現最短路徑的權值不僅可以相加,還可以相乘,不僅可以求最短路徑還可以求最大路徑。