单源最短路模板题,这里尝试用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 31 2 3 41 41 2 12 3 13 4 14 310 2 3 41 42 1 12 3 13 4 1
Sample Output
Case #1: 1Case #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会WAstruct 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; }