题目背景
最短路模板题目。SPFA 或 用堆优化的迪杰斯特拉算法均可实现。
题目描述
成都浣花溪公园是一座有着诗歌文化气息的公园,它以杜甫草堂的历史文化内涵为背景,运用现代园林和建筑设计的前沿理论,以自然雅致的景观和建筑凸现川西文化醇厚的历史底蕴,是一座集将自然景观和城市景观、古典园林和现代建筑艺术有机结合的城市公园。
周末,Mr.Zeng和他儿子在浣花溪公园“诗歌大道”上欣赏诗歌,刚诗兴正浓,Mr.Zeng忽然想起汽车的车门没锁,于是他们要在最快的时间内走出公园赶到公园门口停车场。我们把公园的景点用数字标号(从1 到 N-1),在两个景点中之间会有道路连接,并且Mr.Zeng和他儿子都是素质很高的人,他们不会穿越公园的草坪,只会沿着公园的小路行走。Mr.Zeng想知道从他们当前所处的位置 S 到公园的出口(标号固定为 N)所需要的最短时间。你能帮帮他吗?
输入格式
输入文件的第一行有3 个正整数:N、K、T 并且用空格隔开,分别表示公园景点数目、公园小路条数,以及他们当前所处的景点编号。
接下来 K 行,每行三个整数,表示小路连接的两个景点的编号以及走过这条小路所需要的时间。
输出格式
一个整数,表示他们走出公园所需要的最短时间。
样例数据 1
输入
3 2 1
1 2 3
2 3 4
输出
7
备注
【数据范围】
对于 60% 的数据,保证 N<=1000,K<=10000。
对于 100% 的数据,保证 N<=10000,K<=100000。
对于 100% 的数据,保证结果在 231 内。
一 SPFA+Vector实现
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue> //p.push(t); tmp=p.front(); p.pop();
using namespace std;
struct node
{
int to; //to[i]表示第i条边的终点编号
int len; //len[i]表示第i条边的权值
};
vector <node> bian[200001]; //存储边,由于一般情况下E<<V*V,故在此选用了vector动态数组存储,也可以使用链表存储
queue <int> p; //SPFA队列,用于存储在SPFA算法中的需要松弛的节点
int dist[10001];
bool exist[10001]; //exist[i]=true表示点i已经在队列中
int n,k,t; //点数、变数、当前位置
void init() //数据输入,建立邻接表
{
int i,x,y,w;
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
scanf("%d%d%d",&n,&k,&t); //点数、边数、当前位置t
for(i=1;i<=k;i++)
{
scanf("%d%d%d",&x,&y,&w); //读入起始点、终点、权值
node tmp; //设置一个临时变量,以便存入vector
tmp.to=y; //设置边权
tmp.len=w; //设置连接节点
bian[x].push_back(tmp); //将这条边压入x的表中
tmp.to=x; //反向建边
tmp.len=w;
bian[y].push_back(tmp);
}
}
int main() //主程序
{
init(); //输入数据,
memset(exist,false,sizeof(exist));
for(int i=1;i<=n;i++)
dist[i]=1000000000; //初始化最短距离为一个较大的值,用memset(dis,127,sizeof(dis))求和可能溢出。
dist[t]=0; //起点的最短距离赋值为0
p.push(t); //起点入队
exist[t]=true; //标记起点已经入队
while(!p.empty()) //队列非空,需要继续松弛
{
int tmp=p.front(); //取出队首元素
exist[tmp]=false; //将队首节点标记为未入队
for(int i=0;i<(int)bian[tmp].size();i++) //枚举该从tmp出发的每一条边
{
node *t=&bian[tmp][i]; //由于vector的寻址速度较慢,故在此进行一次优化
if(dist[tmp]+(*t).len < dist[(*t).to]) //更改后距离更短,进行松弛操作
{
dist[(*t).to]=dist[tmp]+(*t).len; //更改边权值
if(!exist[(*t).to]) //对面点没有入队,则将其入队
{
p.push((*t).to); //将对面点压入队列
exist[(*t).to]=true; //标记对面点已经入队
}
}
}
p.pop(); //弹出队首节点
}
printf("%d",dist[n]); //输出到终点的最短路
return 0;
}
二 纯dijkstra
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cctype>
using namespace std;
struct node{
int w;
int num;
};
node heap[10010];
int n,m,k,x,y,i,j,tot,cnt,z,p,s;
int next[200100],w[200100],v[200100],pl[10010],first[10010],dis[10010];
void addedge(int x,int y,int z)
{
tot++;
next[tot]=first[x];
first[x]=tot;
v[tot]=y;
w[tot]=z;
}
void down(int x)
{
int j;
j=x<<1;
while(j<=cnt)
{
if(j<cnt&&heap[j].w>heap[j+1].w) j++;
if(heap[x].w<heap[j].w) break;
else
{
swap(heap[x],heap[j]);
pl[heap[x].num]=x;
pl[heap[j].num]=j;
x=j;
j=j<<1;
}
}
}
void up(int x)
{
int j;
j=x>>1;
while(j!=0&&heap[x].w<heap[j].w)
{
swap(heap[x],heap[j]);
pl[heap[x].num]=x;
pl[heap[j].num]=j;
x=j;
j=j>>1;
}
}
int main()
{
//freopen("hhxgy.in","r",stdin);
scanf("%d%d%d",&n,&m,&s);
tot=0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
memset(dis,127,sizeof(dis));
dis[s]=0;
cnt=0;
for(i=1;i<=n;i++)
{
cnt++;
heap[cnt].w=1E+9;
heap[cnt].num=i;
pl[i]=cnt;
}
heap[pl[s]].w=0;
up(pl[s]);
for(i=1;i<=n;i++)
{
j=heap[1].num;
heap[1]=heap[cnt];
cnt--;
down(1);
p=first[j];
while(p>0)
{
if(dis[j]+w[p]<dis[v[p]])
{
dis[v[p]]=dis[j]+w[p];
heap[pl[v[p]]].w=dis[v[p]];
up(pl[v[p]]);
}
p=next[p];
}
}
printf("%d",dis[n]);
return 0;
}
三 dijkstra+优先队列优化
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
using namespace std;
int n,m,t,x,y,z,tot;
int first[10010],dis[10010];
bool exist[10010];
pair<int,int> temp;
struct node
{
int next;
int to;
int w;
}edge[200010];
inline void create(int x,int y,int z)
{
tot++;
edge[tot].next=first[x];
first[x]=tot;
edge[tot].to=y;
edge[tot].w=z;
}
void read(void)
{
cin>>n>>m>>t;
for(int i=1;i<=m;++i)
{
cin>>x>>y>>z;
create(x,y,z);
create(y,x,z);
}
}
int dijkstra(int s,int t)
{
priority_queue<pair <int,int> >q;
memset(dis,110,sizeof(dis));
dis[s]=0;
temp.first=0;
temp.second=s;
q.push(temp);
while(!q.empty())
{
temp=q.top();
q.pop();
exist[temp.second]=true;
int p=first[temp.second];
int j=temp.second;
while(p>0)
{
if(!exist[edge[p].to]&&dis[edge[p].to]>dis[j]+edge[p].w)
{
dis[edge[p].to]=dis[j]+edge[p].w;
pair<int,int> s;
s.first=-dis[edge[p].to];
s.second=edge[p].to;
q.push(s);
}
p=edge[p].next;
}
}
return dis[t];
}
int main()
{
read();
cout<<dijkstra(t,n);
return 0;
}