货物从一个city到另一个city,中间有收费,经过city时要收费,货物从a到b,花费最少
Floyd:(要是先给出图,然后询问图中2点的cost,而对图没有改变,感觉这个好用点)
注意纪录路径;
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
#include <vector>
#include <stack>
using namespace std;
const int M=150;
int path[M][M],mp[150][150],vis[150],cost[150],pos[M],pre[M];
int n;
const int inf=100000000;
void Floyd()
{
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
path[i][j]=j;///从i到j默认为j,这样,自己到自己也合法了
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
int temp=mp[i][k]+mp[k][j]+pos[k];
if(temp<mp[i][j])
{
mp[i][j]=temp;
path[i][j]=path[i][k];
}
if(temp==mp[i][j]){///字典序最小,这要学习下
if(path[i][j]>path[i][k])
path[i][j]=path[i][k];
}
}
}
int main()
{
int a,b,x,i,j,k;
while(~scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&x);
if(x!=-1)
mp[i][j]=x;
else mp[i][j]=inf;
}
for(i=1;i<=n;i++)
scanf("%d",&pos[i]);
Floyd();
while(scanf("%d%d",&a,&b),a!=-1&&b!=-1)
{
printf("From %d to %d :\n",a,b);
printf("Path: %d",a);
int t=a;
while(t!=b)
{
printf("-->%d",path[t][b]);
t=path[t][b];
}
printf("\n");
printf("Total cost : %d\n\n",mp[a][b]);
}
}
return 0;
}
dijkstra:
这样纪录路径第一次见:当当前点的前驱已经存在时,再改变他的前驱是要考虑字典序,假设a,b是当前u的前驱,可以从u开始往前寻找到起点,然后再从起点开始,要是某一时刻i>j,则返回后面的路径,也就是选择后面的前驱
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
#include <vector>
#include <stack>
using namespace std;
const int M=150;
int path[M],mp[150][150],vis[150],cost[150],pos[M],pre[M];
int n;
const int inf=100000000;
int zid(int s,int a,int b,int cur)//字典顺序
{
int p1[M],p2[M],i=2,j=2;
p1[0]=cur;
p2[0]=cur;//当前位置
p1[1]=a;
p2[1]=b;
while(a!=s)//沿路径返回存入数组
{
p1[i++]=pre[a];
a=pre[a];
}
while(b!=s)
{
p2[j++]=pre[b];
b=pre[b];
}
while(1)//从头开始比较,返回字典序小的。
{
i--,j--;
if(i<0) return p1[1];
else if(j<0) return p2[1];
if(p1[i]>p2[j]) return p2[1];
else if(p1[i]<p2[j]) return p1[1];
}
}
void dijkstra(int st,int ed)
{
int i,j,k;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
cost[i]=inf;
memset(pre,-1,sizeof(pre));
cost[st]=0;
while(true)
{
int v=-1;
for(int u=1;u<=n;u++){
if(!vis[u]&&(v==-1||cost[u]<cost[v]))
v=u;
}
if(v==-1)
break;
vis[v]=1;
for(int u=1;u<=n;u++){
if(!vis[u]&&cost[u]>cost[v]+mp[v][u]+pos[u]){
cost[u]=cost[v]+mp[v][u]+pos[u];
pre[u]=v;
}
else if(!vis[u]&&cost[u]==cost[v]+mp[v][u]+pos[u]){
if(cost[u]<inf&&pre[u]!=-1)
pre[u]=zid(st,pre[u],v,u);
}
}
}
//for(i=1;i<=n;i++)cout<<pre[i]<<" ";cout<<endl;
}
int main()
{
int a,b,x,i,j,k;
while(~scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&x);
if(x!=-1)
mp[i][j]=x;
else mp[i][j]=inf;
}
for(i=1;i<=n;i++)
scanf("%d",&pos[i]);
while(scanf("%d%d",&a,&b),(a!=-1||b!=-1))
{
printf("From %d to %d :\n",a,b);
if(a==b)///由于初始化的时候都是-1,故要是有自己到自己的点输出错误,因此特判下
{
printf("Path: %d\n",a);
printf("Total cost : 0\n\n");
continue;
}
dijkstra(a,b);
stack<int>st;
st.push(b);
for(i=b;i!=a;i=pre[i]){
st.push(pre[i]);
}
printf("Path: %d",a);
st.pop();
while(!st.empty()){
printf("-->%d",st.top());
st.pop();
}
printf("\n");
printf("Total cost : %d\n\n",cost[b]-pos[b]);
}
}
return 0;
}