题意:有n个城市,然后给你n*n的矩阵,map[i][j]代表:值为-1即表示没有从i到j的路,
否则存在i到j的路,并且路费的map[i][j]的值,然后每经过一个城市都要交税(除了起点和终点外)
n等于0时程序结束,然后给你起点和终点,输出从起点和终点的最小费用和路径。
费用=路费+税。
注意:若存在几条路径的费用一样,则要输出字典序最小的那条。
(如:从1->3的费用为3,从1->2->3的费用也是3,那么就要输出第二条路径)
思路:SPFA,Floy,Dijkstra
Floy最方便,其他两个在输出字典序最小的那条路比较麻烦。
SPFA算法:
<在输出字典序最小的路径上面卡死了,WA了8次。实在无力去找题解才发现可以用直接把2条路径放出
在判断哪个是字典序最小,T T>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN = 105;
#define INF 0x3f3f3f3f//无穷大
int inq[MAXN], tax[MAXN], map[MAXN][MAXN];//点是否算过,税,路费
int path[MAXN][MAXN], dist[MAXN][MAXN];//保存路径,值
int n;
bool chang(int v0, int u, int v)//判断字典序是否是最小
{//从v0->...->v的路径,和v0->...->u->v的路径比较取字典序小的
int p1[MAXN], p2[MAXN];
//v0->...->v的路径,v0->...->u->v的路径
int len1 = 0, len2 = 0, tmp;
memset(p1, 0, sizeof(p1));
memset(p2, 0, sizeof(p2));
p1[len1] = v;//v0->...->v的路径
tmp = path[v0][v];
while (tmp != v0)
{
p1[++len1] = tmp;
tmp = path[v0][tmp];
}
p1[++len1] = tmp;
p2[len2] = v;// v0->...->u->v的路径
tmp = u;
while (tmp != v0)
{
p2[++len2] = tmp;
tmp = path[v0][tmp];
}
p2[++len2] = tmp;
while (p1[len1] == p2[len2])//从开始一一判断
{
len1--; len2--;
}
return p2[len2]<p1[len1];
}
void SPFA(int v0)//SPFA算法
{
int i, u;
queue<int>q;
for (i = 1; i <= n; i++)
{
inq[i] = 0;
dist[v0][i] = map[v0][i];
path[v0][i] = v0;
}
dist[v0][v0] = 0;
for (i = 1; i <= n; i++)
{
if (dist[v0][i] != INF)
{
q.push(i);
inq[i] = 1;
}
}
while (!q.empty())
{
u = q.front();
q.pop();
inq[u]--;
for (int v = 1; v <= n; v++)
{
if (dist[v0][v]>(dist[v0][u] + map[u][v] + tax[u]))
{
dist[v0][v] = (dist[v0][u] + map[u][v] + tax[u]);
path[v0][v] = u;
if (!inq[v])
{
q.push(v);
inq[v]++;
}
}
else if (dist[v0][v] == (dist[v0][u] + map[u][v] + tax[u]))
{
if (chang(v0, u, v))//费用相同判断路径是否满足字典序最小
{
path[v0][v] = u;
}
}
}
}
}
int main()
{
while (cin >> n)
{
if (!n)
{
break;
}
int Start, End;
for (int i = 1; i <= n; i++)//路费
{
for (int j = 1; j <= n; j++)
{
cin >> map[i][j];
if (map[i][j] == -1)//无路
{
map[i][j] = INF;
}
}
}
for (int i = 1; i <= n; i++)//对应城市的税
{
cin >> tax[i];
}
for (int i = 1; i <= n; i++)//预先把所有求出来。
{
SPFA(i);
}
while (cin >> Start >> End)//开始和结束,然后按照案例输出
{
if (Start == -1 && End == -1)
{
break;
}
if (Start == End)
{
cout << "From " << Start << " to " << End << " :" << endl;
cout << "Path: " << Start << endl;
cout << "Total cost : " << 0 << endl << endl;
continue;
}
int shorttest[MAXN], k = 0;
cout << "From " << Start << " to " << End << " :" << endl;
cout << "Path: ";
shorttest[k] = End;
while (path[Start][shorttest[k]] != Start)
{
k++;
shorttest[k] = path[Start][shorttest[k - 1]];
}
k++;
shorttest[k] = Start;
for (int j = k; j > 0; j--)
{
cout << shorttest[j] << "-->";
}
cout << shorttest[0] << endl;
cout << "Total cost : " << dist[Start][End] << endl << endl;
}
}
return 0;
}