一点模板

线性素数筛:

欧拉筛:

  定义数组prim[i]表示第i大的素数,isprim[i]表示i是否为素数(是否被筛过)

  从2~n遍历,if(!isprim[i]) prim[++cnt]=i,如果遍历到i时i仍未被筛,则将i记录于prim数组中。接下来开始以i为基数筛除素数,我们发现:所有的合数都能被筛分割为若干数的积。所以无论i是否为素数,我们就从1~cnt依此将所有筛出的素数分别与i的乘积筛除,当i是prim[j]的倍数时,i的倍数必然也是prim[j]的倍数,显然在遍历prim[j]时已经将所有prim[j]的倍数都筛除,故没有必要再用i再筛一遍,break掉。

for(int i=2;i<=n;i++){
    if(!isprim[i]) prim[++cnt]=i;
    for(int j=1;prim[j]<=n/i&&j<=cnt;j++){
        isprim[i*prim[j]]=1;
        if(i%prim[j]==0) break;
    }
}

埃氏筛:

  定义数组prim[i]表示第i大的素数,isprim[i]表示i是否为素数(是否被筛过)

  从2~n依此遍历,若当前遍历的i未被筛除,将i加入prim数组,并将i的所有倍数筛除

  

for(int i=2;i<=n;i++){
    if(!isprim[i]){
        prim[++cnt]=i;
        for(int j=2;j*i<=n;j++){
            isprim[i*j]=1;
        }
    }
}

  埃氏筛相较于欧拉筛较慢,原因是埃氏筛可能会重复筛除同一合数,故欧拉筛的核心剪枝代码即 if(i%prim[j]==0) break;

 

最短路:

floyd:

  作为最短路算法中思路最为暴力,码量最少的算法,floyd也有与之相应的代价:n的三次方的时间复杂度令人难以接受。

  整体思路如下:1~n遍历中间点,再遍历起点,终点,最后更新起点到终点的最短路为起点至中间点的做短路加上中间点至终点的最短路之和。

  实现:定义数组dis[i][j]表示点i至点j的最短路径,初始化为 inf,dis[i][i]=0,在读入边权信息时记录dp[u][v]=w(u表示起点,v表示终点,w表示边权),最后套三层循环即可(注意:遍历顺序为kij)

//记得初始化
memset(dis,0x3f3f3f3f,sizeof(dis));
for(int i=1;i<=n;i++) dis[i][i]=0;
//读入边信息并记录()
for(int i=1;i<=m;i++){
    u=read(),v=read(),w=read();
    dis[u][v]=w;
    dis[v][u]=w;
}

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
                        //取最小值
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        }
    }
}    

 

spfa:

  spfa已死!!!(死不了一点)

  适用于有负权边的最短路,在最劣情况会被卡到O(nm),在没有负权边时建议使用dijkstra,正确性交给玄学组。

   思路:每次取出已经更新过最短路的点,并利用它去进行更新,属于一个贪心的思想

  实现:定义数组dis[i]表示从起始点s至点i的距离,初始时dis[s]=0,其余点dis[i]=inf。在spfa函数中利用STL自带的queue进行取出/放入,vis[i]记录i是否在queue中。

 

void spfa(){
  //初始化
for(int i=1;i<=n;i++) dis[i]=inf; queue<ll>dl; //将起始点s放入
   dl.push(s); dis[s]
=0; while(!dl.empty()){ ll u=dl.front(); dl.pop(); vis[u]=0; for(ll i=head[u];i;i=e[i].nxt){ ll v=e[i].v; if(dis[v]>dis[u]+e[i].w){ //更新最短路
          dis[v]
=dis[u]+e[i].w; //未在队中即放入
          if(!vis[v]){ dl.push(v); vis[v]=1; } } } } }

 

dijkstra:

  作为最短路算法家族中最稳定(?,最高效(?的算法,dijkstra的地位不言而喻,大部分的最短路都是使用dijkstra,毕竟板子也不是很难写嘛QWQ,时间复杂度优化后为O((N+M)logN。

  思路:利用STL(STL大法好啊)中的priority_queue(优先队列),每次取出与起始点的最短路最小的点进行更新,是不是与spfa很像呢,但是dij的复杂度更优也更稳定。

  代码实现:看代码!不过要注意vis[i]记录的是点i是否出队(即是否被利用更新)过。

 

#define pr pair<int,int>
#define mk make_pair

priority_queue<pr,vector<pr>,greater<pr> >dl;
void dij(){
    for(int i=1;i<=n;i++) dis[i]=inf;
    dis[s]=0;
    dl.push(mk(0,s));
    while(!dl.empty()){
        int u=dl.top().second;
        dl.pop();
     //如果已经用过就continue
if(vis[u]) continue; //标记一下
     vis[u]
=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].v; if(dis[v]>dis[u]+e[i].w){ dis[v]=dis[u]+e[i].w; dl.push(mk(dis[v],v)); } } } }

 

posted @ 2023-10-18 11:14  shashadejianzhang  阅读(7)  评论(0编辑  收藏  举报