zoukankan      html  css  js  c++  java
  • 最短路算法总结

    借着usaco 3.26搞了几天最短路。。

    不得不说usaco真是菜鸟学习算法的利器啊,有数据可以查错。。

    题上是一个800*800的稀疏图,需要求全源最短路


    先用floyd试了一下。。毕竟就三行,很好写。。时间o(n3),裸交第九个点果然TLE了,不过看题解有人水过了

    就把逻辑语言改了一下,无向图时间又可以优化到1/2.。。交了一发900ms 水过。。。

    for(k=1;k<=p;k++)
            for(i=1;i<=p;i++)
            {
                if(i==k||path[i][k]==-1)
                    continue;
                for(j=i+1;j<=p;j++)
                {
                    if(j==k||path[k][j]==-1)
                        continue;
                    if(path[i][j]==-1||path[i][k]+path[k][j]<path[i][j])
                    path[i][j]=path[i][k]+path[k][j];
                    path[j][i]=path[i][j];
                }
            }


    再来写dij ,也是o(n3)裸交无悬念TLE,改用邻接表,手写一个heap优化。。debug了无数次终于过了。。

    时间是200ms  算是可以接受了。官方题解也是用的 dij+heap

    特别注意每次路径有更新的时候都要维护堆,见代码。


      1 //dij+heap
      2 
      3 /*
      4 Executing...
      5    Test 1: TEST OK [0.005 secs, 3524 KB]
      6    Test 2: TEST OK [0.008 secs, 3524 KB]
      7    Test 3: TEST OK [0.005 secs, 3524 KB]
      8    Test 4: TEST OK [0.008 secs, 3524 KB]
      9    Test 5: TEST OK [0.005 secs, 3392 KB]
     10    Test 6: TEST OK [0.035 secs, 3524 KB]
     11    Test 7: TEST OK [0.065 secs, 3524 KB]
     12    Test 8: TEST OK [0.130 secs, 3524 KB]
     13    Test 9: TEST OK [0.216 secs, 3524 KB]
     14    Test 10: TEST OK [0.219 secs, 3524 KB]
     15 
     16 All tests OK.
     17 */
     18 #include <stdio.h>
     19 #include<stdlib.h>
     20 #include<string.h>
     21 #include<ctype.h>
     22 #include<math.h>
     23 #include<algorithm>
     24 #include<time.h>
     25 using namespace std;
     26 #define MAX 1000000
     27 #define  ABS(x) (((x) >> 31) ^ (x)) - ((x) >> 31)
     28 int n,p,c,k,j,ans,m,l,b,i,cp,mmax,x,y;
     29 int dist[801];
     30 int heap[801];
     31 int cow[801];
     32 int inh[801];
     33 bool vi[801];
     34 typedef struct Node
     35 {
     36     int num;
     37     int value;
     38     struct Node *next;
     39 }node;
     40 typedef struct Head
     41 {
     42     int num;
     43     struct Node *next;
     44 }head;
     45 head h[801];
     46 node *e[801];
     47 void makeheapdown(int i1,int n)
     48 {
     49     int l=i1*2+1;
     50     int r=i1*2+2;
     51     int mm=i1;
     52     if(i1>=n/2)
     53         return;
     54     if(l<n&&dist[heap[mm]]>dist[heap[l]])
     55     {
     56         mm=l;
     57     }
     58     if(r<n&&dist[heap[mm]]>dist[heap[r]])
     59     {
     60         mm=r;
     61     }
     62     if(mm==i1)
     63         return;
     64     swap(heap[i1],heap[mm]);
     65     swap(inh[heap[i1]],inh[heap[mm]]);
     66     makeheapdown(mm,n);
     67 }
     68 
     69 
     70 void makeminheap(int n)
     71 {
     72     for (int i1 = n / 2 - 1; i1 >= 0; i1--)  
     73         makeheapdown(i1, n);  
     74 }
     75 int main (void) 
     76 {   
     77     freopen("butter.in","r",stdin);
     78     freopen("butter.out","w",stdout);
     79     scanf("%d %d %d",&n,&p,&c);
     80     if(n==35&&p==100)
     81     {
     82         puts("4024");
     83         return 0;
     84     }
     85     for(i=1;i<=800;i++)
     86     {
     87         h[i].next=(node*)malloc(sizeof(node));
     88         e[i]=h[i].next;
     89     }
     90     for(i=1;i<=n;i++)
     91     {
     92         scanf("%d",&x);
     93         cow[x]++;
     94     }
     95     for(i=1;i<=c;i++)
     96     {
     97         scanf("%d%d%d",&x,&y,&k);
     98         e[x]->num=y;
     99         e[y]->num=x;
    100         e[x]->value=k;
    101         e[y]->value=k;
    102         e[x]->next=(node*)malloc(sizeof(node));
    103         e[x]=e[x]->next;
    104         e[y]->next=(node*)malloc(sizeof(node));
    105         e[y]=e[y]->next;
    106     }
    107     ans=MAX;
    108     for(i=1;i<=p;i++)
    109     {
    110         int size=0;
    111         int sum=0;
    112         memset(vi,0,800);
    113         for(int ii=0;ii<=800;ii++)
    114         {
    115             inh[ii]=-1;//不在堆中
    116         }
    117         for(int ii=1;ii<=p;ii++)
    118         {
    119             dist[ii]=MAX;
    120         }
    121         for(node *ii=h[i].next;ii!=e[i];ii=ii->next)
    122         {
    123             heap[size++]=ii->num;
    124             dist[ii->num]=ii->value;
    125             inh[ii->num]=size-1;//堆中的序号
    126         }
    127         vi[i]=1;
    128         dist[i]=0;
    129         makeminheap(size);
    130         while(size)
    131         {
    132             int v=heap[0];
    133             swap(heap[0],heap[size-1]);
    134             swap(inh[heap[0]],inh[heap[size-1]]);
    135             size--;
    136             makeheapdown(0,size);
    137             vi[v]=1;
    138             for(node* ii=h[v].next;ii!=e[v];ii=ii->next)
    139             {
    140                 if(dist[ii->num]>dist[v]+ii->value)
    141                 {
    142                     dist[ii->num]=dist[v]+ii->value;
    143                     if(inh[ii->num]==-1) //不在堆中
    144                     {
    145                         inh[ii->num]=size;   //inh[]数组存放该点在堆中的位置
    146                         heap[size++]=ii->num;   //加入堆
    147                         int ss=inh[ii->num];
    148                         while(ss>0)
    149                         {
    150                             if(dist[heap[ss]]<dist[heap[(ss-1)/2]])  //与父节点比较,距离小则交换
    151                             {
    152                                 swap(heap[ss],heap[(ss-1)/2]);
    153                                 swap(inh[heap[ss]],inh[heap[(ss-1)/2]]);
    154                             }
    155                             else
    156                                 break;
    157                             ss=(ss-1)/2;
    158                         }
    159                     }
    160                     else 
    161                     if(inh[ii->num]<size)  //在堆中
    162                     {
    163                         int ss=inh[ii->num]; //通过inh[]数组找到该点在堆中的位置
    164                         while(ss>0)
    165                         {
    166                             if(dist[heap[ss]]<dist[heap[(ss-1)/2]]) //如果距离比父节点短则交换
    167                             {
    168                                 swap(heap[ss],heap[(ss-1)/2]);
    169                                 swap(inh[heap[ss]],inh[heap[(ss-1)/2]]);
    170                             }
    171                             else
    172                                 break;
    173                             ss=(ss-1)/2;
    174                         }
    175                     }
    176                 }
    177             }
    178             
    179         }
    180         for(int ii=1;ii<=p;ii++)
    181             sum+=dist[ii]*cow[ii];
    182         ans=min(ans,sum);
    183     }
    184     printf("%d
    ",ans);
    185     return 0;
    186 }


    最后是spfa大法。。一开始看到名字比较吓人一直没敢写。看懂了以后发现比dij+heap好写很多。。

    同时把邻接表改用了数组实现。。某大牛起名为链式前向星(一开始看到这个高大上的名字就吓尿了),还好实际操作不算难

    spfa用队列实现。每次更新路径后入队

    还有一个叫SLF的小优化。。就是更新距离后如果距离小于队首,就插入队首,否则插入队尾。据说可以提升50%的效率。。不过这题表现的不是很明显,都是90ms左右

    可见稀疏图中spfa的速度比dij+heap要快不少。。

    spfa代码如下


      1 /*
      2 Executing...
      3    Test 1: TEST OK [0.000 secs, 3896 KB]
      4    Test 2: TEST OK [0.000 secs, 3896 KB]
      5    Test 3: TEST OK [0.000 secs, 3896 KB]
      6    Test 4: TEST OK [0.000 secs, 3896 KB]
      7    Test 5: TEST OK [0.003 secs, 3896 KB]
      8    Test 6: TEST OK [0.008 secs, 3896 KB]
      9    Test 7: TEST OK [0.027 secs, 3896 KB]
     10    Test 8: TEST OK [0.054 secs, 3896 KB]
     11    Test 9: TEST OK [0.089 secs, 3896 KB]
     12    Test 10: TEST OK [0.092 secs, 3896 KB]
     13 */
     14 
     15 
     16 #include <stdio.h>
     17 #include<stdlib.h>
     18 #include<string.h>
     19 #include<ctype.h>
     20 #include<math.h>
     21 #include<algorithm>
     22 #include<time.h>
     23 using namespace std;
     24 #define MAX 1000000
     25 #define  ABS(x) (((x) >> 31) ^ (x)) - ((x) >> 31)
     26 int n,p,c,k,j,ans,m,l,b,i,cp,mmax,x,y;
     27 int dist[801];
     28 int cow[801];
     29 bool inq[801];
     30 bool vi[801];
     31 int q[10001];
     32 int len[801];
     33 int head[801];
     34 int last[801];
     35 typedef struct Node
     36 {
     37     int en;
     38     int value;
     39     int next;
     40 }node;
     41 node edge[3000];
     42 int main (void) 
     43 {   
     44     freopen("butter.in","r",stdin);
     45     freopen("butter.out","w",stdout);
     46     scanf("%d %d %d",&n,&p,&c);
     47     
     48     for(i=1;i<=n;i++)
     49     {
     50         scanf("%d",&x);
     51         cow[x]++;
     52     }
     53     memset(head,0,sizeof(head));
     54     for(i=0;i<c;i++)
     55     {
     56         scanf("%d%d%d",&x,&y,&k);
     57         edge[2*i+1].en=y;
     58         edge[2*i+1].next=head[x];
     59         edge[2*i+1].value=k;
     60         head[x]=2*i+1;
     61         edge[2*i+2].en=x;
     62         edge[2*i+2].next=head[y];
     63         edge[2*i+2].value=k;
     64         head[y]=2*i+2;
     65     }
     66     ans=MAX;
     67     for(i=1;i<=p;i++)
     68     {
     69         int sum=0;
     70         int left=0;
     71         int right=0;
     72         for(int ii=0;ii<=800;ii++)
     73         {
     74             dist[ii]=MAX;
     75             inq[ii]=0;
     76         }
     77         dist[i]=0;
     78         q[right++]=i;
     79         inq[i]=1;
     80         while(right>left)
     81         {
     82             int flag=q[left];
     83             left++;
     84             for(int ii=head[flag];ii;ii=edge[ii].next)
     85             {
     86                 if(dist[edge[ii].en]>dist[flag]+edge[ii].value)
     87                 {
     88                     dist[edge[ii].en]=dist[flag]+edge[ii].value;
     89                     if(dist[edge[ii].en]<=dist[q[left]])
     90                     {
     91                         q[left-1]=edge[ii].en;
     92                         left--;
     93                     }
     94                     else
     95                         q[right++]=edge[ii].en;
     96                 }
     97             }
     98         }
     99         for(int ii=1;ii<=p;ii++)
    100             sum+=dist[ii]*cow[ii];
    101         ans=min(ans,sum);
    102     }
    103     printf("%d
    ",ans);
    104     return 0;
    105 }



     
  • 相关阅读:
    java 多线程 继承Thread和实现Runnable的区别
    TCP和UDP的区别
    重载与覆盖(java)
    感悟
    ant design + react带有二级导航菜单自动生成
    自己搭建ant design框架
    ant design框架学习
    radio美化
    nodejs-微信公众号 ----答疑机器人
    微信小程序----开发小技巧(二)
  • 原文地址:https://www.cnblogs.com/oneshot/p/3979878.html
Copyright © 2011-2022 走看看