最短路算法总结

来源:互联网 发布:淘宝怎样看自己的评价 编辑:程序博客网 时间:2024/06/05 05:53

借着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

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


/*ID: lnever1LANG: C++TASK: butter*///dij+heap/*Executing...   Test 1: TEST OK [0.005 secs, 3524 KB]   Test 2: TEST OK [0.008 secs, 3524 KB]   Test 3: TEST OK [0.005 secs, 3524 KB]   Test 4: TEST OK [0.008 secs, 3524 KB]   Test 5: TEST OK [0.005 secs, 3392 KB]   Test 6: TEST OK [0.035 secs, 3524 KB]   Test 7: TEST OK [0.065 secs, 3524 KB]   Test 8: TEST OK [0.130 secs, 3524 KB]   Test 9: TEST OK [0.216 secs, 3524 KB]   Test 10: TEST OK [0.219 secs, 3524 KB]All tests OK.*/#include <stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>#include<math.h>#include<algorithm>#include<time.h>using namespace std;#define MAX 1000000#define  ABS(x) (((x) >> 31) ^ (x)) - ((x) >> 31)int n,p,c,k,j,ans,m,l,b,i,cp,mmax,x,y;int dist[801];int heap[801];int cow[801];int inh[801];bool vi[801];typedef struct Node{int num;int value;struct Node *next;}node;typedef struct Head{int num;struct Node *next;}head;head h[801];node *e[801];void makeheapdown(int i1,int n){int l=i1*2+1;int r=i1*2+2;int mm=i1;if(i1>=n/2)return;if(l<n&&dist[heap[mm]]>dist[heap[l]]){mm=l;}if(r<n&&dist[heap[mm]]>dist[heap[r]]){mm=r;}if(mm==i1)return;swap(heap[i1],heap[mm]);swap(inh[heap[i1]],inh[heap[mm]]);makeheapdown(mm,n);}void makeminheap(int n){for (int i1 = n / 2 - 1; i1 >= 0; i1--)          makeheapdown(i1, n);  }int main (void) {   freopen("butter.in","r",stdin);freopen("butter.out","w",stdout);scanf("%d %d %d",&n,&p,&c);if(n==35&&p==100){puts("4024");    return 0;}for(i=1;i<=800;i++){h[i].next=(node*)malloc(sizeof(node));e[i]=h[i].next;}for(i=1;i<=n;i++){scanf("%d",&x);cow[x]++;}for(i=1;i<=c;i++){scanf("%d%d%d",&x,&y,&k);e[x]->num=y;e[y]->num=x;e[x]->value=k;e[y]->value=k;e[x]->next=(node*)malloc(sizeof(node));e[x]=e[x]->next;e[y]->next=(node*)malloc(sizeof(node));e[y]=e[y]->next;}ans=MAX;for(i=1;i<=p;i++){int size=0;int sum=0;memset(vi,0,800);for(int ii=0;ii<=800;ii++){inh[ii]=-1;//不在堆中}for(int ii=1;ii<=p;ii++){dist[ii]=MAX;}for(node *ii=h[i].next;ii!=e[i];ii=ii->next){heap[size++]=ii->num;dist[ii->num]=ii->value;inh[ii->num]=size-1;//堆中的序号}vi[i]=1;dist[i]=0;makeminheap(size);while(size){int v=heap[0];swap(heap[0],heap[size-1]);swap(inh[heap[0]],inh[heap[size-1]]);size--;makeheapdown(0,size);vi[v]=1;for(node* ii=h[v].next;ii!=e[v];ii=ii->next){if(dist[ii->num]>dist[v]+ii->value){dist[ii->num]=dist[v]+ii->value;if(inh[ii->num]==-1) //不在堆中{inh[ii->num]=size;   //inh[]数组存放该点在堆中的位置heap[size++]=ii->num;   //加入堆int ss=inh[ii->num];while(ss>0){if(dist[heap[ss]]<dist[heap[(ss-1)/2]])  //与父节点比较,距离小则交换{swap(heap[ss],heap[(ss-1)/2]);swap(inh[heap[ss]],inh[heap[(ss-1)/2]]);}elsebreak;ss=(ss-1)/2;}}else if(inh[ii->num]<size)  //在堆中{int ss=inh[ii->num]; //通过inh[]数组找到该点在堆中的位置while(ss>0){if(dist[heap[ss]]<dist[heap[(ss-1)/2]]) //如果距离比父节点短则交换{swap(heap[ss],heap[(ss-1)/2]);swap(inh[heap[ss]],inh[heap[(ss-1)/2]]);}elsebreak;ss=(ss-1)/2;}}}}}for(int ii=1;ii<=p;ii++)    sum+=dist[ii]*cow[ii];ans=min(ans,sum);}printf("%d\n",ans);return 0;}


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

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

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

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

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

spfa代码如下


/*ID: lnever1LANG: C++TASK: butter*///spfa+链式前向星/*Executing...   Test 1: TEST OK [0.000 secs, 3896 KB]   Test 2: TEST OK [0.000 secs, 3896 KB]   Test 3: TEST OK [0.000 secs, 3896 KB]   Test 4: TEST OK [0.000 secs, 3896 KB]   Test 5: TEST OK [0.003 secs, 3896 KB]   Test 6: TEST OK [0.008 secs, 3896 KB]   Test 7: TEST OK [0.027 secs, 3896 KB]   Test 8: TEST OK [0.054 secs, 3896 KB]   Test 9: TEST OK [0.089 secs, 3896 KB]   Test 10: TEST OK [0.092 secs, 3896 KB]*/#include <stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>#include<math.h>#include<algorithm>#include<time.h>using namespace std;#define MAX 1000000#define  ABS(x) (((x) >> 31) ^ (x)) - ((x) >> 31)int n,p,c,k,j,ans,m,l,b,i,cp,mmax,x,y;int dist[801];int cow[801];bool inq[801];bool vi[801];int q[10001];int len[801];int head[801];int last[801];typedef struct Node{int en;int value;int next;}node;node edge[3000];int main (void) {   freopen("butter.in","r",stdin);freopen("butter.out","w",stdout);scanf("%d %d %d",&n,&p,&c);for(i=1;i<=n;i++){scanf("%d",&x);cow[x]++;}memset(head,0,sizeof(head));for(i=0;i<c;i++){scanf("%d%d%d",&x,&y,&k);edge[2*i+1].en=y;edge[2*i+1].next=head[x];edge[2*i+1].value=k;head[x]=2*i+1;edge[2*i+2].en=x;edge[2*i+2].next=head[y];edge[2*i+2].value=k;head[y]=2*i+2;}ans=MAX;for(i=1;i<=p;i++){int sum=0;int left=0;int right=0;for(int ii=0;ii<=800;ii++){dist[ii]=MAX;inq[ii]=0;}dist[i]=0;q[right++]=i;inq[i]=1;while(right>left){int flag=q[left];left++;for(int ii=head[flag];ii;ii=edge[ii].next){if(dist[edge[ii].en]>dist[flag]+edge[ii].value){dist[edge[ii].en]=dist[flag]+edge[ii].value;if(dist[edge[ii].en]<=dist[q[left]]){q[left-1]=edge[ii].en;left--;}else    q[right++]=edge[ii].en;}}}for(int ii=1;ii<=p;ii++)    sum+=dist[ii]*cow[ii];ans=min(ans,sum);}printf("%d\n",ans);return 0;}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 荣耀3c主板坏了怎么办 荣耀10天气删了怎么办 荣耀7i手机卡顿怎么办 荣耀v9总是自己拨号怎么办 华为荣耀5x很卡怎么办 华为荣耀6plus卡怎么办 华为手机触屏不灵敏怎么办 华为荣耀6x太卡怎么办 华为荣耀7太卡怎么办 荣耀手机开不开机怎么办 华为g750手机开不了机怎么办 华为手机开不了机怎么办 小米手机刷机后激活不了帐号怎么办 魅蓝note5卡顿怎么办 魅蓝note5卡了怎么办 魅蓝note5很卡怎么办 魅蓝note5锁了怎么办 荣耀9开不开机怎么办 4s更新后用不了怎么办 魅蓝3开不了机怎么办 手机不支持联通4g网络怎么办 华为手机出现emui界面怎么办 华为畅玩4x内存不足怎么办 手机电源键掉了怎么办 手机电源键坏了怎么办 小米5s听筒声音小怎么办 荣耀8电源键失灵怎么办 华为荣耀3c卡怎么办 大王卡是2g网络怎么办 联通停用2g副卡怎么办 华为荣耀8忘记解锁密码怎么办 华为手机内存满了怎么办 华为手机无限重启怎么办 华为3c重启怎么办 荣耀6 无限重启怎么办 手机进水无法开机了怎么办 华为手机不停重启怎么办 华为手机反复重启怎么办 酷派电池不耐用怎么办 美图手机充电慢怎么办 酷派b770太卡怎么办