@Chilling
2017-04-19T12:09:08.000000Z
字数 6624
阅读 1619
最短路
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条商店到赛场的路线。
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
将两点之间的信息保存在邻接矩阵中,使用dijkstra算法寻找最短路。dis数组存入的是从起点到某点的最短距离,最开始初始化要最大,因此
memset(dis,127,sizeof(dis));在dij函数中每找到短的一条路径就根据这一路径更新其他路径。
while(m--){scanf("%d%d%d",&a,&b,&c);if(c<ma[a][b]){ma[a][b]=c;ma[b][a]=c; //双向}}
void dij(){int i,j,x,pos;for(i=1;i<=n;i++)dis[i]=ma[1][i]; //从1到i点的距离vis[1]=1; //标记起点for(i=1;i<n;i++) //n个点,也就是该题中的路口{x=INF;for(j=1;j<=n;j++){if(vis[j]==0&&dis[j]<x) //没有经过某位置{x=dis[j]; //从所有没有标记的点中,选择一个dis最小的pos=j;}}vis[pos]=1; //标记这个最小的点for(j=1;j<=n;j++) //并且用这个最小的点更新其他路径if(vis[j]==0&&dis[j]>dis[pos]+ma[pos][j]) //如果经过pos点再到j的距离比原来的更短,更新dis[j]=dis[pos]+ma[pos][j];}}
#include<stdio.h>#include<string.h>#define INF 1e9int ma[111][111],m,n,dis[111],vis[111];void dij(){int i,j,x,pos;for(i=1;i<=n;i++)dis[i]=ma[1][i]; //从1到i点的距离vis[1]=1;for(i=1;i<n;i++){x=INF;for(j=1;j<=n;j++){if(vis[j]==0&&dis[j]<x){x=dis[j];pos=j;}}vis[pos]=1;for(j=1;j<=n;j++)if(vis[j]==0&&dis[j]>dis[pos]+ma[pos][j]) //如果经过pos点再到j的距离比原来的更短,更新dis[j]=dis[pos]+ma[pos][j];}}int main(){int a,b,c;while(scanf("%d%d",&n,&m),n+m){memset(ma,127,sizeof(ma));memset(vis,0,sizeof(vis));while(m--){scanf("%d%d%d",&a,&b,&c);if(c<ma[a][b]){ma[a][b]=c;ma[b][a]=c; //双向}}dij();printf("%d\n",dis[n]);}return 0;}
邻接表可以用于无向图,也可以用于有向图,用数组实现链表,比vector的时间复杂度更低一点。
void add(int st,int en,int val){a[num].en=en;a[num].val=val;a[num].next=pos[st];pos[st]=num;num++;}
void dij(){int i,j,x,id;dis[1]=0; //起点for(i=1;i<=n;i++){x=INF;for(j=1;j<=n;j++){if(vis[j]==0&&dis[j]<x) //没有经过并且距离更短,就使用这个点{x=dis[j]; //从所有没有标记的点中,选择一个dis最小的id=j;}}vis[id]=1; //使用后标记for(j=pos[id];j!=-1;j=a[j].next) //与这个点相连的其他点{if(dis[a[j].en]>dis[id]+a[j].val) //如果原来到这点的距离比现在的更长,用现在的距离更新dis[a[j].en]=dis[id]+a[j].val;}}}
#include<stdio.h>#include<string.h>#define INF 1e9struct node{int en,val,next;}a[100005];int vis[111],pos[111],dis[111],num,n,m;void add(int st,int en,int val){a[num].en=en;a[num].val=val;a[num].next=pos[st]; //好像是加到前面的意思……再理解= =不行就记住pos[st]=num;num++;}void dij(){int i,j,x,id;dis[1]=0; //起点for(i=1;i<=n;i++){x=INF;for(j=1;j<=n;j++){if(vis[j]==0&&dis[j]<x) //没有经过并且距离更短,就使用这个点{x=dis[j];id=j;}}vis[id]=1; //使用后标记for(j=pos[id];j!=-1;j=a[j].next) //这里也不是很清楚{if(dis[a[j].en]>dis[id]+a[j].val) //如果原来到这点的距离比现在的更长,用现在的距离更新dis[a[j].en]=dis[id]+a[j].val;}}}int main(){int a,b,c;while(scanf("%d%d",&n,&m),n+m){memset(vis,0,sizeof(vis));memset(pos,-1,sizeof(pos));memset(dis,127,sizeof(dis)); //距离初始化最大值num=0;while(m--){scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c); //无向图,添加两个方向}dij();printf("%d\n",dis[n]); //到n的最短时间}return 0;}
如果不用优先队列优化,每次找到最短距离需要二重循环,复杂度为,使用优先队列,复杂度为。
其实这个并不是很懂……都是照着模板打的
struct node2{int id,val; //id是尾位置吧大概……node2(int id1=0,int val1=0) //构造函数{id=id1;val=val1;}friend bool operator <(node2 x,node2 y) //重载<符号{return x.val>y.val;}};
建立邻接表:和不用优先队列优化的一样,此处省略。懒得粘
dijkstra+优先队列:
void dij(){dis[1]=0; //起点node2 now;priority_queue<node2>q;q.push(node2(1,0)); //因为前面有构造函数,所以此处可以直接写node2(1,0)//1表示的现在的点,0是距离while(!q.empty()){int i;now=q.top();q.pop();if(vis[now.id]==1) continue;vis[now.id]=1; //选取没有标记的点放入另一个集合中,然后标记它for(i=pos[now.id];i!=-1;i=a[i].next) //与上一个相同,找它相连的其他未标记的点{if(vis[a[i].en]==0&&dis[a[i].en]>dis[now.id]+a[i].val) //松弛操作{dis[a[i].en]=dis[now.id]+a[i].val;q.push(node2(a[i].en,dis[a[i].en]));}}}}
#include<stdio.h>#include<queue>#include<string.h>using namespace std;int n,m,vis[111],num,pos[111],dis[111];struct node1{int en,val,next;}a[100005];struct node2{int id,val; //id是位置node2(int id1=0,int val1=0) //构造函数{id=id1;val=val1;}friend bool operator <(node2 x,node2 y) //重载<符号{return x.val>y.val;}};void add(int st,int en,int val){a[num].en=en;a[num].val=val;a[num].next=pos[st];pos[st]=num;num++;}void dij(){dis[1]=0;node2 now;priority_queue<node2>q;q.push(node2(1,0));while(!q.empty()){int i;now=q.top();q.pop();if(vis[now.id]==1) continue; //该点走过vis[now.id]=1;for(i=pos[now.id];i!=-1;i=a[i].next){if(dis[a[i].en]>dis[now.id]+a[i].val){dis[a[i].en]=dis[now.id]+a[i].val;q.push(node2(a[i].en,dis[a[i].en]));}}}}int main(){int a,b,c;while(scanf("%d%d",&n,&m),n+m){num=0;memset(dis,127,sizeof(dis));memset(vis,0,sizeof(vis));memset(pos,-1,sizeof(pos));while(m--){scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c);}dij();printf("%d\n",dis[n]);}return 0;}
vector是一种容器,其实就相当于数组,里面自带有许多函数(
但是我不会用而且觉得自己没有学过C++更不会STL),比通过数组实现的邻接矩阵更容易理解,但是貌似调用vector里面的函数时间复杂度更高一点。
vector<node> v[11111];,vector的编号(0-11111)表示起点,node中存终点和到终点的时间
while(m--){scanf("%d%d%d",&a,&b,&c);v[a].push_back(node(b,c));v[b].push_back(node(a,c));//起点a,终点b,时间c存入vector,起点b终点a时间c存入}
struct node{int en,val; //en是目标点,val是到该点的时间node(int en1=0,int val1=0) //构造函数,然后就可以在下面直接写node(a,b){en=en1;val=val1;}friend bool operator <(node x,node y) //重载<符号{return x.val>y.val;}};
void dij(){dis[1]=0;//起点priority_queue<node>q; //优先队列优化,每次弹出时间最短的q.push(node(1,dis[1])); //压入起点和diswhile(!q.empty()){node now,next;now=q.top();q.pop();if(vis[now.en]==1)continue;vis[now.en]=1; //选取没有标记的点放入另一个集合中,然后标记它for(int i=0;i<v[now.en].size();i++){next=v[now.en][i]; //!!开了vector[11111]貌似相当于一个二维的数组,但是不会用…然后去看了别人怎么写的if(dis[next.en]>now.val+next.val) //松弛操作{dis[next.en]=now.val+next.val;q.push(node(next.en,dis[next.en]));}}}}
#include<stdio.h>#include<queue>#include<string.h>#include<vector>#define INF 1e9using namespace std;int n,m,vis[111],dis[111];struct node{int en,val; //id是位置node(int en1=0,int val1=0) //构造函数= =然后就可以在下面直接写node(a,b){en=en1;val=val1;}friend bool operator <(node x,node y) //重载<{return x.val>y.val;}};vector<node> v[11111]; //vector的编号表示起点,node中存终点和到终点的时间void dij(){dis[1]=0;//起点priority_queue<node>q; //优先队列优化,每次弹出时间最短的q.push(node(1,dis[1]));while(!q.empty()){node now,next;now=q.top();q.pop();if(vis[now.en]==1)continue;vis[now.en]=1;for(int i=0;i<v[now.en].size();i++){next=v[now.en][i];if(dis[next.en]>now.val+next.val){dis[next.en]=now.val+next.val;q.push(node(next.en,dis[next.en]));}}}}int main(){int a,b,c;while(scanf("%d%d",&n,&m),n+m){memset(dis,127,sizeof(dis));memset(vis,0,sizeof(vis));while(m--){scanf("%d%d%d",&a,&b,&c);v[a].push_back(node(b,c));v[b].push_back(node(a,c));//起点a,终点b,时间c存入vector,起点b终点a时间c存入}dij();printf("%d\n",dis[n]);for(int i=0;i<11111;i++)v[i].clear();}return 0;}