caioj1088·SPFA算法模板题·最短路
来源:互联网 发布:新部落冲突4级地震数据 编辑:程序博客网 时间:2024/06/03 15:19
求距离一般有Floyd,Dijkstra,Ford,SPFA算法等
Floyd最简单也最容易理解
SPFA算是最常用也是解决大部分题目的算法之一
下面来看一道例题
1088: 最短路(模版 SPFA算法 元问题 by scy)
时间限制: 1 Sec 内存限制: 128 MB
题目描述
【题意】
给出一个图,起始点是1,结束点是N,边是双向的。求点1到点N的最短距离。哈哈,这就是标准的最短路径问题。
【输入格式】
第一行为两个整数N(1≤N≤10000)和M(0≤M≤200000)。N表示图中点的数目,M表示图中边的数目。
下来M行,每行三个整数x,y,c表示点x到点y之间存在一条边长度为c。(x≠y,1≤c≤10000)
【输出格式】
输出一行,一个整数,即为点1到点N的最短距离。
如果点1和点N不联通则输出-1。
【样例1输入】
2 1
1 2 3
【样例1输出】
3
【样例2输入】
3 3
1 2 5
2 3 5
3 1 2
【样例2输出】
2
【样例3输入】
6 9
1 2 7
1 3 9
1 5 14
2 3 10
2 4 15
3 4 11
3 5 2
4 6 6
5 6 9
【样例3输出】
20
2/题解
a数组为邻接矩阵存图
d数组是点到出发点的距离
list为队列,head,与tail为头尾指针
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int a[1100][1100];int d[11000];int list[11000],head,tail;bool v[11000];int n;int main(){ int x,y,c,m,st,ed; scanf("%d%d",&n,&m); memset(a,63,sizeof(a)); for (int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&c); if(a[x][y]>c){//可能重复录入,记录最小边打个擂台 a[x][y]=c; a[y][x]=c; } } //初始化d,后面才有更新的必要 st=1;ed=n; for (int i=1;i<=n;i++) d[i]=999999999; d[st]=0; memset(v,false,sizeof(v));v[st]=true; list[1]=st;head=1;tail=2; while (head!=tail){ x=list[head];//单独取出 for (int y=1;y<=n;y++){ if(d[y]>d[x]+a[x][y]){//判断是否能继续更新 d[y]=d[x]+a[x][y]; if(v[y]==false){//判断是否已经入队没有则... v[y]=true; list[tail]=y; tail++;if (tail==n+1) tail=1;//循环数组,跳转至队头 } } } list[head]=0; head++;if (head==n+1) head=1;//循环队列 v[x]=false; } printf("%d\n",d[n]);}
但上面的算法只能过40%左右的点
于是做出进一步改进
#include<cstdio>#include<cstring>using namespace std;struct bian//表示有向边的结构体,构建编目录{ int x,y,d,next;// x表示出发点,y表示终点,next表示和x相连的上一条边的编号};bian a[210000]; int len,last[11000];//a的个数是边的个数,last的个数是点的个数。//last[i]表示最后一条和点i相连的边的编号。int d[11000];//d[i]表示目前i和出发点的最短距离void ins(int x,int y,int d)// ins函数的功能是建立一条边{ len++;//全局增加一条有向边,len一开始为0 a[len].x=x; a[len].y=y;a[len].d=d;//边的赋值 a[len].next=last[x]; last[x]=len;//边的联系}int list[11000],head,tail;//list用来存排队准备更新其他人的点,head表示头,tail表示尾bool v[11000];// v[i]等于true表示点i在队列list中,等于false表示点i不再队列list中int n;int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int x,y,c,m,st,ed; scanf("%d%d",&n,&m); len=0; memset(last,0,sizeof(last));//注意构图之前一定要初始化,不然后果很严重! for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&c);//题目给出的是无向边,而我们的边目录是有向边 ins(x,y,c);//建立正向边 ins(y,x,c);//建立反向边 }//1:初始化d,这样后面才有更新的必要 st=1;ed=n; for(int i=1;i<=n;i++) d[i]=999999999; d[st]=0;//出发点为0//2:初始化v, 一开始所有点都没有 memset(v,false,sizeof(v)); v[st]=true;//点1作为出发点已经进入list//3:初始化队列list list[1]=st; head=1;tail=2;//队列的头是有人的,队列的尾tail指的位置是没人的 while(head!=tail)//只要头不等于尾,就表示还有人需要更新别人 { x=list[head];//取出准备好更新别人的人x for(int k=last[x]; k ; k=a[k].next )//重点理解!k首相等于和x相连的最后一条边的编号。那么倒数第二条和x相连的边的编号是多少呢?在a[最后一条].next可以找到 { y=a[k].y; if(d[y]>d[x]+a[k].d)//更新是一定要的 { d[y]=d[x]+a[k].d; if(v[y]==false)//如果被更新了,那么要考虑进入队列(考虑是否去更新别人) { v[y]=true; list[tail]=y; tail++; if(tail==n+1) tail=1;//如果tail超过队列的最后一个,则变为第一个 } } }//x已经完成更新别人的任务,就要退出队列list,那么需要做什么呢? list[head]=0; head++; if(head==n+1) head=1; //如果head超过队列的最后一个,则变为第一个 v[x]=false; } printf("%d\n",d[n]);//最后输出终点到出发点的距离 return 0;}
(直接在网站复制过来了,,懒得打了。。。
阅读全文
2 0
- caioj1088·SPFA算法模板题·最短路
- 最短路+hdu+spfa算法模板题
- 最短路【SPFA】算法模板
- 最短路SPFA算法模板
- 最短路 SPFA模板
- 最短路 【spfa】 模板
- 最短路~spfa模板
- 最短路-SPFA 模板
- 模板-最短路//spfa
- 模板整理——图论·最短路·spfa
- hdu 2544 最短路 spfa模板题
- 最短路--SPFA算法
- 最短路SPFA算法
- 最短路: SPFA算法
- spfa算法 最短路
- SPFA最短路算法
- 最短路之SPFA模板
- 最短路spfa dijkstra模板
- 8.odoo入门——jinja2入门(一)
- 笔记11--Js基础知识
- leetcode题解-378. Kth Smallest Element in a Sorted Matrix
- Unity3D学习记录——NGUI Lable
- 51Nod 1119 机器人走方格 组合数学
- caioj1088·SPFA算法模板题·最短路
- JS第二章
- 2017.7.25 暑期第一次模拟赛(By Geng4512 大犇) Day 2 小结
- Android Studio中ADB.exe启动不起来。
- Android Studio 使用 Gradle 打包 Jar
- 通过崩溃地址找出源代码的出错行(未实践)
- Object.create
- 使用CSS实现上下左右居中
- 链表的基本操作