• 最短路基础代码(题型)


    1.求起点到其他各点的最短路长度

    [例题:洛谷4779]

    dijsktra
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 500050;
    inline int read() {
        char c = getchar();
        int x = 0, f = 1;
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        return x * f;
    }
    struct edge{
        int v,w,next;
    }e[N];
    int h[N],dis[N],cnt,n,m,s;
    struct node{  //
        int u,d;
        bool operator <(const node&rhs)const{
          return d > rhs.d;
        }
    };
    inline void add(int u,int v,int w)
    {
      e[++cnt].next = h[u];
      e[cnt].v = v;
      e[cnt].w = w;
      h[u] = cnt;    
    } 
    inline void dij()
    {
        for(int i = 1; i <= n; i++)  dis[i] = INT_MAX;
        dis[s] = 0;
        priority_queue<node>q;
        q.push((node){s,0});
        while(!q.empty()){
            node fr = q.top();
            q.pop();
            int u = fr.u,
                d = fr.d;
            if(d!=dis[u]) continue; // 懒惰删除 
    /*因为每次松弛操作后,要删除堆中原有的节点,
    这样很不方便,所以就加上这一句话判断是否被删除过。
    (查找时人为跳过标记过的节点)*/ 
            for(int i = h[u]; i; i = e[i].next){
                int v = e[i].v,
                    w = e[i].w;
                if(dis[u] + w < dis[v]){
                    dis[v] = dis[u] + w;
                    q.push((node){v,dis[v]});
                }
            }
        }
    }
    int main()
    {
      n = read();m = read();s = read();
      for(int i = 1; i <= m; i++){
          int x = read(),
              y = read(),
              z = read();
              add(x,y,z);
      }
      dij();
      for(int i = 1; i <= n; i++)  printf("%d ",dis[i]);
      return 0;
    }
    SPFA
    //对,spfa他死了,luogu标准测的32分
    //
    求一个节点到其他所有节点的最短路长度 #include<bits/stdc++.h> using namespace std; #define ll long long const int N = 1000500; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); return x * f; } struct edge{ int v, next, w; }e[N<<1]; int len,n,m,s,t,h[N],dis[N],vis[N]; inline void add(int a,int b, int c){ e[++len].next = h[a]; e[len].v = b; e[len].w = c; h[a] = len; } inline void spfa(int s) { for(int i = 1; i <= n; i++) dis[i] = INT_MAX; queue<int>q; q.push(s); dis[s] = 0, vis[s] = 1; while(!q.empty()){ int x = q.front(); q.pop(); vis[x] = 0; //他不在队列里了 for(register int i = h[x];i;i = e[i].next){ int v = e[i].v, w = e[i].w; if(dis[v] > dis[x] + w){ dis[v] = dis[x] + w; if(!vis[v]){ q.push(v); vis[v] = 1; } } } } } int main() { n = read(); m = read(); s = read(); for(register int i = 1; i <= m; i++ ){ int a = read(), b = read(), c = read(); add(a,b,c); } spfa(s); for(int i = 1; i <= n; i++) printf("%d ",dis[i]); return 0; }

    【弱化】求点1到点N的最短路长度

    [例题:caioj1088]

    SPFA
    #include<cstdio> #include<cstring> using namespace std; struct bian//表示有向边的结构体,构建编目录 { int x,y,d,next;// x表示出发点,y表示终点,next表示和x相连的上一条边的编号 }; bian a[210000]; int len,n,last[11000];//a的个数是边的个数,last的个数是点的个数。 //last[i]表示最后一条和点i相连的边的编号。 int d[11000];//d[i]表示目前i和出发点的最短距离 int list[11000],head,tail;//list用来存排队准备更新其他人的点,head表示头,tail表示尾 void ins(int x,int y,int d)// ins函数的功能是建立一条边 { len++;//全局增加一条有向边,len一开始为0 a[len].x=x; a[len].y=y;a[len].d=d;//边的赋值 a[len].next=last[x]; last[x]=len;//边的联系 (顺序不可以变,是为了遍历所有与某一点的边) } bool v[11000];// v[i]等于true表示点i在队列list中,等于false表示点i不再队列list中 int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int x,y,c,m,st,ed; scanf("%d%d",&n,&m); len=0; memset(last,0,sizeof(last));//注意构图之前一定要初始化,不然后果很严重! for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&c);//题目给出的是无向边,而我们的边目录是有向边 ins(x,y,c);//建立正向边 ins(y,x,c);//建立反向边 } //1:初始化d,这样后面才有更新的必要 st=1;ed=n; for(int i=1;i<=n;i++) d[i]=999999999; d[st]=0;//出发点为0 //2:初始化v, 一开始所有点都没有 memset(v,false,sizeof(v)); v[st]=true;//点1作为出发点已经进入list //3:初始化队列list list[1]=st; head=1;tail=2;//队列的头是有人的,队列的尾tail指的位置是没人的 while(head!=tail)//只要头不等于尾,就表示还有人需要更新别人 { x=list[head];//取出准备好更新别人的人x for(int k=last[x]; k ; k=a[k].next )//重点理解!k首相等于和x相连的最后一条边的编号。那么倒数第二条和x相连的边的编号是多少呢?在a[最后一条].next可以找到 { y=a[k].y; if(d[y]>d[x]+a[k].d)//更新是一定要的 { d[y]=d[x]+a[k].d; if(v[y]==false)//如果被更新了,那么要考虑进入队列(考虑是否去更新别人) { v[y]=true; list[tail]=y; tail++; if(tail==n+1) tail=1;//如果tail超过队列的最后一个,则变为第一个 } } } //x已经完成更新别人的任务,就要退出队列list,那么需要做什么呢? list[head]=0; head++; if(head==n+1) head=1; //如果head超过队列的最后一个,则变为第一个 v[x]=false; } printf("%d ",d[n]);//最后输出终点到出发点的距离 return 0; }

     [hdu2544] 

    https://www.cnblogs.com/phemiku/p/11524092.html

    2.最短路计数(求1到其他顶点的最短路条数)

      BFS 

     边权为1时 https://www.luogu.org/problem/P1144

    #include<bits/stdc++.h>
    #define sc(x) scanf("%d",&x)
    #define fr(i,n)  for(register int i = 1; i <= n; i++)
    #define mod 100003
    const int N = 1e6 + 9;
    int cnt[N],x,y,t,dep[N];
    bool vis[N];
    std::vector<int>g[N];
    std::queue<int>q;
    int main()
    {
      int n,m;
      sc(n),sc(m);
      fr(i,m){
          sc(x),sc(y);
          g[x].push_back(y);
          g[y].push_back(x);
      }
      cnt[1] = 1, vis[1] = 1;
      q.push(1);
      while(!q.empty()){
          x = q.front();
        q.pop();
        for(int i = 0; i < g[x].size();i++){
            t = g[x][i];
            if(!vis[t]) dep[t] = dep[x] + 1, vis[t] = 1, q.push(t);
            if(dep[t] == dep[x] + 1) cnt[t] = (cnt[t] + cnt[x]) % mod;
        } 
      }
      fr(i,n) printf("%d
    ",cnt[i]);
      return 0;
    }

    Dijkstra

    满堂花醉三千客,一剑霜寒十四州
  • 相关阅读:
    js正则表达式验证【引用网址】
    Chart控件的使用实例
    C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
    C#进阶系列——WebApi 接口参数不再困惑:传参详解
    C#进阶系列——WebApi 路由机制剖析:你准备好了吗?
    【UiPath 中文教程】02
    八幅漫画理解使用JSON Web Token设计单点登录系统
    JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案
    webservice 教程
    IBM MQ 使用指南
  • 原文地址:https://www.cnblogs.com/phemiku/p/11537316.html
Copyright © 2020-2023  润新知