• [USACO09JAN]安全出行Safe Travel


    Gremlins最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的 地是牛棚_i).每一个gremlin只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经.所以它 们在牛_i到牛棚_i之前的最后一条牛路上等牛_i. 当然,牛不愿意遇到Gremlins,所以准备找 一条稍微不同的路经从牛棚_1走到牛棚_i.所以,请你为每一头牛_i找出避免gremlin_i的最 短路经的长度.

    和以往一样, 农场上的M (2 <= M <= 200,000)条双向牛路编号为1..M并且能让所有牛到 达它们的目的地, N(3 <= N <= 100,000)个编号为1..N的牛棚.牛路i连接牛棚a_i (1 <= a_i <= N)和b_i (1 <= b_i <= N)并且需要时间t_i (1 <=t_i <= 1,000)通过. 没有两条牛路连接同样的牛棚,所有牛路满足a_i!=b_i.在所有数据中,牛_i使用的牛棚_1到牛 棚_i的最短路经是唯一的.

    输入输出格式

    输入格式:

    • Line 1: Two space-separated integers: N and M

    • Lines 2..M+1: Three space-separated integers: a_i, b_i, and t_i

    输出格式:

    • Lines 1..N-1: Line i contains the smallest time required to travel from pasture_1 to pasture_i+1 while avoiding the final cowpath of the shortest path from pasture_1 to pasture_i+1. If no such path exists from pasture_1 to pasture_i+1, output -1 alone on the line.

    输入输出样例

    输入样例#1: 复制
    4 5 
    1 2 2 
    1 3 2 
    3 4 4 
    3 2 1 
    2 4 3 
    
    输出样例#1: 复制
    3 
    3 
    6 
    
    思路:首先dijkstra跑一遍最短路(卡spfa),单源最短路构成一颗生成树,要求到源点1的次短路,显然必须要通过不在树上的边,这样我们只要求min{w(u,v)+d(u)+d(v)-d(f)}。
    从上面式子看出,经过点f的环中w(u,v)+d(u)+d(v)最小时即是次短路,那么只要将不在树上的边与树上的边构成的环的权值从小到大排序,就能贪心得到答案,并用并查集维护那些点被更新过。
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #define N 100010
    using namespace std;
    int n,m,cnt,u,v,w,head[N],cnt2,dis[N],num,f[N],fa[N],set[N];//f数组为i到1的次短路
    bool vis[N];
    struct node{
      int next,to,dis;
    }e[N*10],g[N*10];
    void add(int u,int v,int w)
    {
      e[++cnt].next=head[u],e[cnt].to=v,e[cnt].dis=w,head[u]=cnt;
    }
    void add2(int u,int v,int w)
    {
      g[++cnt2].next=u,g[cnt2].to=v,g[cnt2].dis=w;
    }
    void dij(int u)
    {
      priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
      memset(dis,0x3f3f3f3f,sizeof(dis));
      q.push(make_pair(0,u)),dis[u]=0;
      while(!q.empty())
        {
          int u=q.top().second;q.pop();
          if(vis[u])continue;vis[u]=1;
          for(int i=head[u];i;i=e[i].next)
        {
          int v=e[i].to;
          if(dis[v]>dis[u]+e[i].dis)
            {
              dis[v]=dis[u]+e[i].dis;
              fa[v]=u;
              q.push(make_pair(dis[v],v));
            }
        }
        }
    }
    bool cmp(const node&a,const node&b)
    {
      return a.dis<b.dis;
    }
    int find(int x)
    {
      return x==set[x]?x:set[x]=find(set[x]);
    }
    void kk(node x)
    {
      int u=x.next,v=x.to,w=x.dis;
      while(find(u)!=find(v))
        {
          num++;
          if(dis[find(u)]<dis[find(v)])swap(u,v);
          f[find(u)]=min(f[find(u)],w-dis[find(u)]);//更新当前结点
          u=set[find(u)]=fa[find(u)];
        }
    }
    int main()
    {
      memset(f,0x3f3f3f3f,sizeof(f));
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)set[i]=i;
      for(int i=1;i<=m;i++)scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
      dij(1);
      for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=e[j].next)
          {
        int u=i,v=e[j].to;
        if(u!=fa[v]&&v!=fa[u])//边不在最短路树上
          add2(u,v,dis[u]+dis[v]+e[j].dis);//加上环权值和
          }
      sort(g+1,g+1+cnt2,cmp);//按环权排序
      for(int i=1;i<=cnt2&&num<=n-1;i++)//枚举非树上结点,每次把环上没被赋值过的点赋上值,并查集记录树上哪些点被更新过
        kk(g[i]);
      for(int i=2;i<=n;i++)
        {
          if(f[i]<0x3f3f3f3f)printf("%d
    ",f[i]);
          else puts("-1");
        }
      return 0;
    }
  • 相关阅读:
    Redis操作命令大全
    Redis实用监控工具一览
    Redis缓存雪崩、缓存穿透、缓存击穿、缓存降级、缓存预热、缓存更新
    Redis GEO地理位置信息,查看附近的人
    详解redis持久化
    详解Supervisor进程守护监控
    详解Redis Cluster集群
    arduino使用rfid
    树莓派控制WS2812
    Arduino读取温湿度dh11+烟雾气体MQ2+彩灯ws2812
  • 原文地址:https://www.cnblogs.com/lxykk/p/7757494.html
Copyright © 2020-2023  润新知