• 最短路


                                                                                                                                 道路和航线

    题目描述

    原题来自:USACO 2011 Jan. Gold

    Farmer John 正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到T个城镇,编号为1到T。这些城镇之间通过R条道路(编号为1到R)和P条航线(编号为1到P)连接。每条道路i或者航线i连接城镇Ai到Bi,花费为Ci

    对于道路,0<=Ci<=1e4,然而航线的花费很神奇,花费Ci可能是负数。道路是双向的,可以从Ai到Bi,也可以从Bi到Ai,花费都是 Ci 。然而航线与之不同,只可以从Ai到Bi

    事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策保证:如果有一条航线可以从Ai到Bi,那么保证不可能通过一些道路和航线从Bi回到Ai。由于 FJ 的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇S把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。

    第一种方法:因为有负权用优化的spfa,但会卡掉一两个点

     1 #include<cstdio>
     2 #include<deque>
     3 #include<cstring>
     4 using namespace std;
     5 const int maxn=25000+10,maxm=150000+10,inf=0x3f3f3f3f;
     6 struct Edge{
     7     int w,to,next;
     8 }e[maxm];
     9 struct Node{
    10     int id,dis;
    11     Node(){};
    12     Node(int x,int y){
    13         id=x;
    14         dis=y;
    15     }
    16     bool operator<(const Node &a)const{
    17         return dis>a.dis;
    18     }
    19 };
    20 int head[maxm],tot=0;
    21 void Insert(int a,int b,int c){
    22      e[++tot].to=b;
    23      e[tot].w=c;
    24      e[tot].next=head[a];
    25      head[a]=tot;
    26 }
    27 int dis[maxn];
    28 void spfa(int x){
    29      int vis[maxn];
    30      deque<Node> q;
    31      memset(dis,0x3f,sizeof(dis));
    32      memset(vis,0,sizeof(vis));
    33      dis[x]=0;
    34      vis[x]=1;
    35      q.push_back(Node(x,0));
    36      while(!q.empty()){
    37          Node t=q.front();
    38          q.pop_front();
    39          int u=t.id;
    40          vis[u]=0;
    41          for(int i=head[u];i;i=e[i].next){
    42              int v=e[i].to;
    43              if(dis[v]>dis[u]+e[i].w){
    44                  dis[v]=dis[u]+e[i].w;
    45                  if(!vis[v]){
    46                      if(!q.empty()&&dis[v]<q.front().dis){
    47                         q.push_front(Node(v,dis[v]));
    48                      }//若dis[v]小于队列中最小的距离,将其置为最小,减少出入队的次数,以此优化
    49                      else{
    50                         q.push_back(Node(v,dis[v]));
    51                      }
    52                      vis[v]=1;
    53                  }
    54              }
    55          }
    56      }
    57 }
    58 int main(){
    59     int n,r,p,s;
    60     scanf("%d%d%d%d",&n,&r,&p,&s);
    61     for(int i=1;i<=r;i++){
    62        int x,y,z;
    63        scanf("%d%d%d",&x,&y,&z);
    64        Insert(x,y,z);
    65        Insert(y,x,z);
    66     }
    67     for(int i=1;i<=p;i++){
    68        int x,y,z;
    69        scanf("%d%d%d",&x,&y,&z);
    70        Insert(x,y,z);
    71     }
    72     spfa(s);
    73     for(int i=1;i<=n;i++){
    74        if(dis[i]!=inf) printf("%d
    ",dis[i]);
    75        else printf("NO PATH
    ");
    76     }
    77     return 0;
    78 }
    View Code

    第二种方法:根据题意可发现道路相连的点看成一个个连通块,若切断航线就会被独立出来,将其缩点,会变成一个有负权的DAG图,拓扑排序即可求出最小距离。而若涉及到连通块中的点,因为只有正权,跑Dijkstra即可

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn=25000+10,maxm=150000+10,inf=0x3f3f3f3f;
      4 int dis[maxn];
      5 vector<int> g[maxn];
      6 queue<int> toq;
      7 struct Edge{
      8     int w,to,next;
      9 }e[maxm];
     10 struct Node{
     11     int id,dis;
     12     Node(){};
     13     Node(int x,int y){
     14         id=x;
     15         dis=y;
     16     }
     17     bool operator<(const Node &a)const{
     18         return dis>a.dis;
     19     }
     20 };
     21 int head[maxm],tot=0;
     22 void Insert(int a,int b,int c){
     23      e[++tot].to=b;
     24      e[tot].w=c;
     25      e[tot].next=head[a];
     26      head[a]=tot;
     27 }
     28 int rd[maxn],belong[maxn],cnt;
     29 void dfs(int u){
     30      belong[u]=cnt;
     31      g[cnt].push_back(u);//记录每个连通块包含的点
     32      for(int i=head[u];i;i=e[i].next){
     33          int v=e[i].to;
     34          if(belong[v]) continue;//返祖边
     35          dfs(v);
     36      }
     37 }
     38 void Dijkstra(int x){
     39      priority_queue<Node> q;
     40      for(int i=0;i<g[x].size();i++){
     41          int u=g[x][i];
     42          q.push(Node(u,dis[u]));
     43      }//确保用连通块中的每一个点更新其他距离
     44      while(!q.empty()){
     45          Node t=q.top();
     46          q.pop();
     47          int u=t.id;
     48          if(dis[u]!=t.dis) continue;//保证dis不因有负权影响下面是否连通的判断
     49          for(int i=head[u];i;i=e[i].next){
     50              int v=e[i].to;
     51              if(belong[v]!=x){
     52                  rd[belong[v]]--;
     53                  if(rd[belong[v]]==0){
     54                      toq.push(belong[v]);
     55                  }  //入度为0,进队
     56              }
     57              if(dis[u]<inf&&dis[v]>dis[u]+e[i].w){//若dis==inf则x与u不连通,不需更新
     58                  dis[v]=dis[u]+e[i].w;
     59                  if(belong[v]==x){
     60                       q.push(Node(v,dis[v]));//若v与x属于一个连通块,进队,更新其他点
     61                  }
     62              }             
     63          }
     64      }
     65 }
     66 void tpsort(int x){
     67      for(int i=1;i<=cnt;i++){
     68          if(rd[i]==0) toq.push(i);//入度为0的连通块入队
     69      }
     70      memset(dis,0x3f,sizeof(dis));
     71      dis[x]=0;
     72      while(!toq.empty()){
     73          int u=toq.front();
     74          toq.pop();
     75          Dijkstra(u);
     76      }
     77 }
     78 int main(){
     79     int n,r,p,s;
     80     scanf("%d%d%d%d",&n,&r,&p,&s);
     81     for(int i=1;i<=r;i++){
     82        int x,y,z;
     83        scanf("%d%d%d",&x,&y,&z);
     84        Insert(x,y,z);
     85        Insert(y,x,z);
     86     }
     87     for(int i=1;i<=n;i++){
     88        if(!belong[i]){
     89            cnt++;
     90            dfs(i);//确定每个连通块中的点,和其数量
     91        }
     92     }
     93     for(int i=1;i<=p;i++){
     94        int x,y,z;
     95        scanf("%d%d%d",&x,&y,&z);
     96        Insert(x,y,z);
     97        if(belong[x]!=belong[y]){
     98             rd[belong[y]]++;
     99        }//确定每个连通块的入度,跑拓扑用
    100     }
    101     tpsort(s);
    102     for(int i=1;i<=n;i++){
    103        if(dis[i]!=inf) printf("%d
    ",dis[i]);
    104        else printf("NO PATH
    ");
    105     }
    106     return 0;
    107 }
    View Code
  • 相关阅读:
    浙江工业大学校赛 小马哥和数列
    浙江工业大学校赛 XiaoWei的战斗力
    浙江工业大学校赛 猜猜谁是我
    浙江工业大学校赛 竹之书(大数,同余定理)
    浙江工业大学校赛 画图游戏 BugZhu抽抽抽!!
    浙江工业大学校赛 画图游戏
    pta 天梯地图 (Dijkstra)
    Atom打造 c/c++编译环境(忙了一个上午)
    HRBUST
    CSU 1808 地铁 (Dijkstra)
  • 原文地址:https://www.cnblogs.com/HZOIDJ123/p/13279221.html
Copyright © 2020-2023  润新知