最短路算法总结
来源:互联网 发布:淘宝怎样看自己的评价 编辑:程序博客网 时间: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
- 最短路算法总结
- 最短路算法总结
- 最短路算法总结
- 最短路算法总结
- 最短路算法总结
- 最短路算法总结
- 算法总结:最短路
- 最短路算法总结
- 【算法笔记】最短路总结
- 最短路算法学习总结和感悟
- 最短路的四种算法总结
- 求最短路算法的一个总结
- JavaScript最短路算法
- 最短路 Dijkstra算法
- 最短路算法
- 最短路算法
- 最短路-Floyd算法
- 算法训练 最短路
- Android联系人数据库全解析-2.0以上
- Android属性之build.prop生成过程分析
- Struts1和Struts2的区别和对比(完整版)
- 转载保存关于ros的一些有用网页
- 安全解决方案对于VPN - SSL或IPsec
- 最短路算法总结
- JS get实现数据列表的修改
- MongoDB使用
- Android视觉规范-间距规范与文字规范单位换算(dip、sp与px) 此博文包含图片
- 利用VB获取基于OLEDB连接sqlserver数据库的字符串
- 在weblogic11g上发布项目遇到的一个错误(不支持web-app_3_0)
- .ne webservice report
- RandomAccessFile 随机读写
- adt bundle如何安装及使用SVN