单源最短路模板题,这里尝试用SPFA,但有几点细节:
①不能用邻接矩阵,开不下1e5*1e5的二维数组;邻接表vector<p>G[maxn]或链式前向星
②注意用longlong,而且INF定义为LONG_LONG_MAX(不要手打整数,因为默认为int,也可强制类型转换(1e16))
复习:long double,unsigned long long...log
1e16 double
999999999999999... int(溢出)
③最短路算法复习:
a.Dijkstra
一开始觉得和Prim很像,都用到贪心,而且选好点后,更新与这点相关(可到达)的数据,但是贪心的对象有细微不同。
Prim是dis一维数组(表示目前已加入生成树的点,到其相邻结点的权值的最小值)进行贪心,没有dp的思想;
Dijkstra对松弛操作的dis一维数组(表示起点到该点的最小距离,还要加上前面已经得到的最小距离,而前面得到局部最小距离,必须也是全局最小距离,这是算法成立的关键,也是为什么Dijkstra只支持非负边,这里最优子结构的思想,类似dp)贪心,取出最小所在的的结点P,然后对该点P邻点(这里类似广搜),更新数据,vis标记该点P,最后往复上述操作直到所有vis的点被标记上。
dis 1 2 3 4 5 6 (绿色表示当前取得,红色表示vis标记过已经取过的点,蓝色代表更新的点)
0 7 9 ∞ ∞ 14
0 7 9 ∞ ∞ 14
0 7 9 22 ∞ 14
0 7 9 20 ∞ 11
0 7 9 20 ∞ 11
0 7 9 20 20 11
...
0 7 9 20 20 11
具体思想看看这篇博客:
b.Floyd
联想到之前离散数学学的传递闭包Warshall求法:
①k 1-n 找到第k列
②i 1-n 找到值为1的行,下标i→if(a[i][k]==1)→则执行③j 1-n a[i][j]=a[k][j]
用到三重循环,Floyd与之类似,只不过思想有所改变:
找到第k个结点作为中间点,比较i到j直达的距离和加了中间点k距离。
c.
最近市面出现了一款全新的游戏,Absolute Counter Online,简称ACO。Asuna跟她的男票Kirito也都跑去玩这个了。
把Kirito传送了K次之后,Asuna终于气消了。。。
最新情报,在这个游戏里,也有传说中的圣剑excalibur,俗称咖喱棒。作为耍剑的高手Kirito自然不能放过这么好的一个机会。游戏里有N那个城市,同时有M条道路连接不同的两个城市,经过不同的道路耗费的时间是不同的。当前Kirito在编号为S的城市,得到的消息是圣剑藏在编号为T的城市中。因为游戏中其他玩家也想抢圣剑,所以Kirito希望用最快的速度到达城市T。而Asuna发现,每个城市中都会有一个传送用的魔法阵,可以快速将他们传送到任意一个城市(没错,这次他们是两人一起传送),不同的魔法阵传送的用时也不同。
Input
多组数据,EOF结尾。
每组数据先输入两个整数N和M,表示有N个城市及M条无向边。
2 <= N <= 100000
1 <= M <= 200000
接下来一行,输入N个整数,第i个数字表示城市i的魔法阵,传送的用时Ui, 1<=Ui<=1000000000。
接下来输入两个整数S和T,表示Kirito他们所在城市,以及圣剑所在城市,1<=S,T<=N 且 S!=T。
接下来M行,每行三个整数X, Y, W,表示一条连接X和Y两个城市的无向边,通过这条边的耗时为W,1<=X,Y<=N, X!=Y, 1<=W<=1000000000。
Output
对于每组数据,输出格式为:“Case #k: u”,k表示第k组数据,从1开始,u表示最短用时。
Sample Input
4 3
1 2 3 4
1 4
1 2 1
2 3 1
3 4 1
4 3
10 2 3 4
1 4
2 1 1
2 3 1
3 4 1
Sample Output
Case #1: 1
Case #2: 3
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=300001;
const long long inf =(long long)(1e16); //不能直接打数字!!!默认是int会WA
struct edge
{
int from,to,next;
long long w;
}e[1000001];
int head[maxn];
int vis[maxn];
int vis2[maxn];
long long dist[maxn];
long long mo[maxn];
int n,m,t;
void add(int i,int j,long long w)
{
e[t].from=i;
e[t].to=j;
e[t].w=w;
e[t].next=head[i];
head[i]=t++;
}
long long spfa(int s,int end,int n)
{
queue <int> q;
for(int i=1;i<=n;i++)
dist[i]=inf;
memset(vis,false,sizeof(vis));
memset(vis2,false,sizeof(vis2));
q.push(s);
dist[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dist[v]>dist[u]+e[i].w)
{
dist[v]=dist[u]+e[i].w;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
long long res= dist[end];
for(int i=1;i<=n;i++)
{
res=min(res,dist[i]+mo[i]);
}
return res;
}
int main()
{
int a,b,s,e;
long long c;
int cnt=1;
// scanf("%d%d",&n,&m);
while(cin>>n>>m)
{
memset(mo,0,sizeof(mo));
t=0;
memset(head,-1,sizeof(head));
//memset(dist,0,sizeof(dist));
for(int i=1;i<=n;i++)
{
scanf("%lld",&mo[i]);
}
scanf("%d%d",&s,&e);
while(m--)
{
scanf("%d%d%lld",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
long long res1= spfa(s,e,n);
printf("Case #%d: %lld\n",cnt,res1);
cnt++;
}
return 0;
}