最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 20581 Accepted Submission(s): 8811
Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间
Sample Input
2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
Sample Output
3 2
Source
Recommend
lcy
题解:最短路径....下面给出部分最短路径解法以作总结(flody、dij、dij+priority queue、bellman、spfa)
flody算法:邻接矩阵存图,用3重for循环对枚3个点,以2条路径不断构成1条更短的路径
//flody算法
#include<stdio.h>
#include<string.h>
#define INF 1<<29
int c[105][105],n;
void init()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
c[i][j]=i==j?0:INF;
}
void flody()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(c[i][j]>c[i][k]+c[k][j])
c[i][j]=c[i][k]+c[k][j];
}
int main()
{
int x,y,z,m,i;
while(scanf("%d%d",&n,&m)>0)
{
if(n==0&&m==0) break;
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
c[x][y]=c[y][x]=z;
}
flody();
printf("%d\n",c[1][n]);
}
return 0;
}
裸dij算法:邻接矩阵or邻接表存图,每次提取出未更新过且距离起点最近的点,标记该点,并通过该点更新其他点到起点的距离,每一个点只更新一次,一共更新n次
//裸dij算法
#include<stdio.h>
#include<string.h>
#define INF 1<<28
int c[105][105],l[105],mark[105],n;
void init()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
c[i][j]=INF;
for(l[1]=0,i=2;i<=n;i++) l[i]=INF;
memset(mark,0,sizeof(mark));
}
void dij()
{
int i,j,m,make;
for(i=0;i<n;i++)
{
for(m=INF,j=1;j<=n;j++)
{
if(!mark[j]&&l[j]<m)
make=j,m=l[j];
}
mark[make]=1;
for(j=1;j<=n;j++)
{
if(!mark[j]&&c[make][j]<INF&&l[j]>l[make]+c[make][j])
l[j]=l[make]+c[make][j];
}
}
}
int main()
{
int x,y,z,m,i;
while(scanf("%d%d",&n,&m)>0)
{
if(n==0&&m==0) break;
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
c[x][y]=c[y][x]=z;
}
dij();
printf("%d\n",l[n]);
}
return 0;
}
dij+priority queue优化:邻接矩阵or邻接表存图,在提取未更新过且最近的点的时候利用优先队列来提取,标记该点,且对每个可进行更新的点入队,这个点必定未更新过,直到优先队列为空则停止更新
//优先队列dij
#include<stdio.h>
#include<string.h>
#include<queue>
#define INF 1<<28
using namespace std;
struct point{
int id,dis;
}cc;
bool operator <(const point &a,const point &b)
{
return b.dis<a.dis;
}
priority_queue<point>q;
int c[105][105],l[105],mark[105],n;
void init()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
c[i][j]=INF;
for(l[1]=0,i=2;i<=n;i++) l[i]=INF;
memset(mark,0,sizeof(mark));
}
void dij()
{
int i,x;
cc.id=1,cc.dis=0;
q.push(cc);
while(!q.empty())
{
cc=q.top();
q.pop();
x=cc.id;
mark[x]=1;
for(i=1;i<=n;i++)
{
if(!mark[i]&&l[i]>l[x]+c[i][x])
{
l[i]=l[x]+c[i][x];
cc.id=i,cc.dis=l[i];
q.push(cc);
}
}
}
}
int main()
{
int x,y,z,m,i;
while(scanf("%d%d",&n,&m)>0)
{
if(n==0&&m==0) break;
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
c[x][y]=c[y][x]=z;
}
dij();
printf("%d\n",l[n]);
}
return 0;
}
bellman:可以计算有负权,用普通的结构体将所有边存起来。对所有的边进行n-1次松弛更新点的最短距离,若某一次松弛已经不能更新,则可以退出循环,若n-1次更新后仍然能继续更新,则存在负权。
//bellman算法
#include<stdio.h>
#include<string.h>
#define INF 1<<28
int p[105],n;
int dis[105],cou;
struct edge
{
int x,y,l;
}v[20005];
void init()
{
int i=2;
for(;i<=n;i++) dis[i]=INF;
cou=dis[1]=0;
}
void add(int x,int y,int z)
{
v[cou].x=x;
v[cou].y=y;
v[cou++].l=z;
}
void bellman()
{
int flag=1,i,j;
for(j=0;j<n-1&&flag;j++)
{
flag=0;
for(i=0;i<cou;i++)
{
if(dis[v[i].x]+v[i].l<dis[v[i].y])
{
flag=1;
dis[v[i].y]=dis[v[i].x]+v[i].l;
}
}
}
}
int main()
{
int m,i,x,y,z;
while(scanf("%d%d",&n,&m)>0)
{
if(n==0&&m==0) break;
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
bellman();
printf("%d\n",dis[n]);
}
}
spfa算法:可计算负权,由于一般不用该算法处理稠密图,所以一般用邻接表存图。由起点入队开始,每一次从队列出一个点,由该点出发更新其他点,对于每一个被更新且未入队的点都使其进入队列,每一个点可多次入队但不可以同时出现在队列2次,直到队列为空。
//spfa算法
#include<stdio.h>
#include<string.h>
#define INF 1<<28
int p[105],inse,n;
int dis[105],que[20005],mark[105];
struct linjiebiao
{
int data,l,next;
}v[10005];
void init()
{
int i;
for(i=0;i<=n;i++)
{
p[i]=-1;
dis[i]=INF;
mark[i]=0;
}
dis[1]=0;
}
void add(int x,int y,int z)
{
v[inse].next=p[x];
v[inse].data=y;
v[inse].l=z;
p[x]=inse++;
}
void spfa()
{
int sta=0,fin=1,temp,x;
que[0]=mark[0]=1;
while(sta<fin)
{
x=que[sta++];
mark[x]=0;
temp=p[x];
while(temp!=-1)
{
if(dis[v[temp].data]>dis[x]+v[temp].l)
{
dis[v[temp].data]=dis[x]+v[temp].l;
if(!mark[v[temp].data])
{
que[fin++]=v[temp].data;
mark[v[temp].data]=1;
}
}
temp=v[temp].next;
}
}
}
int main()
{
int m,i,x,y,z;
while(scanf("%d%d",&n,&m)>0)
{
if(n==0&&m==0) break;
init();
for(inse=i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
spfa();
printf("%d\n",dis[n]);
}
}