%大赛D--链式前向星+SPFA(BFS)+各种数据类型+各种最短路复习

 

单源最短路模板题,这里尝试用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         ∞        14

           7              ∞    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;  
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值