噩梦。。真是噩梦,GB同学给初学者留下的这个任务,显然有点高估我们的实力了。
我做这道题的时候是一波N折,先后产生了五个版本,现在我的思考过程以及代码都弄出来,大家借鉴一下:
1、刚开始是最最原始的方法,dijkstra暴力求解,显然效率是非常低的,在本机上跑了9s,简单优化一下,八秒。。然后就再也没有提升的空间了。ps:在网上搜索到了测试数据,经验证,和浙大的数据完全一样,但是poj上的就不一样,我估计是poj上删掉了某组数据,而且他上面的时间限制是5s,在zoj上是1s。。
2、在网上看优先队列可以优化,我又把stl中priority_queue的东东看了看,写出来之后感觉时间上是有减少的 ,提交poj,4s过但是zojWA我后来仔细研究了算法的整个过程,发现当我把一个点加入到队列中后,如果他的距离被更新之后就会被再次加入队列中,所以我那个算法是错误的,虽然可以优化,我不会,如果优化成功的话,在zoj能跑300ms。。。这两个oj时间怎么差这么多呢??PS:我后来又了解到Johnson算法,用临界表+斐波那契堆。。。我呆呆的看了好长时间,最后问cw的时候,他说大黄都搞不清楚那个是怎么用的,我faint。。。。
3、然后想到了floyd,求每个顶点对的最短路径,这个还没有讲,我简单看了看,没有看懂,好像要用到矩阵运算的知识。我比葫芦画瓢写了一个,然后结果竟然是对的,提交zoj,超时。提交poj,938ms。。。。这算是第一次AC吧。由于Floyd代码简单,没有什么优化的方法了,再想下一种方法。
4、优先队列那个我是不会用了,那就只用临界表吧,我是用数组实现的。最后在poj2672ms过,zoj的TLE。
5、在将近绝望的时候,我想到了cw提到过的spfa,我仿佛看到了救星,,,,曙光貌似就在前方。baidu+google,学了学他,果然跟bfs有点相像。具体想看的点这里 。
虽然我将近三天才做完,但是我的收获不仅仅是这一道题,图论的算法我多少都看了看。各种名词也不再感觉陌生和害怕了,有些知识只要你敢于去学,你会发现当你最终懂得时候你用的时间并不多。。。。继续努力~!
本题代码几经修改很冗长,有很多可以改的,懒了。。直接贴:
#include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; struct node { int zhi; int shunxu; } temp; const int INF=9999999; struct node biao[501][510]; int nearest[501]; int hash[501]; int dist[501],loca[101]; int station,secs,pre,i,j,k,final; int from,t,to,weight,maxx,now; char a[100]; int main(void) { int max,min; queue<int> q; while( gets(a)!= NULL ) { sscanf(a,"%d%d",&station,&secs);//输入部分有点纠结 for( i = 1 ; i <= 500 ; i++ ) for( j = 1 ; j <= 500 ; j++ ) { biao[i][j].zhi=INF; biao[i][j].shunxu=0; } for( i = 1 ; i <= secs ; i++ ) biao[i][0].zhi=1; if( secs == 1 && station ) { printf("1/n"); gets(a); gets(a); continue; } for( i = 1 ; i <= station ; i++ ) scanf("%d",&loca[i]); getchar(); while( gets(a) != NULL && strlen(a) != 0 ) { sscanf(a,"%d%d%d",&from,&to,&weight); biao[from][++(biao[from][0].zhi)].zhi=weight; biao[from][biao[from][0].zhi].shunxu=to; biao[to][++(biao[to][0].zhi)].zhi=weight; biao[to][biao[to][0].zhi].shunxu=from; } for( j = 1 ;j <= 500 ; j++ ) nearest[j]=INF; for( i = 1 ; i <= station ; i++ ) { while( !q.empty() ) q.pop(); for( j = 1 ; j <= secs ; j++ ) dist[j]=INF; memset(hash,0,sizeof(hash)); dist[loca[i]]=0; hash[loca[i]]=1; q.push(loca[i]); while( !q.empty() ) //spfa的关键过程 { now = q.front(); q.pop(); hash[now]=false; for( k = 2 ; k <= biao[now][0].zhi ; k++ ) { t = biao[now][k].shunxu; if( dist[t] > dist[now] + biao[now][k].zhi ) { dist[t] = dist[now] + biao[now][k].zhi; if(!hash[t]) { hash[t]=true; q.push(t); } } } } for(j=1;j<=secs;j++) if(nearest[j]>dist[j]) nearest[j]=dist[j]; } for(i=1,max=-1;i<=secs;i++) if(nearest[i]>max) max=nearest[i]; for( i = 1 ; i <= secs ; i++ ) { while( !q.empty() ) q.pop(); for( j = 1 ; j <= station ; j++ ) if( loca[j] == i ) continue; if(nearest[i]==0) continue; for( j = 1 ; j <= secs ; j++ ) dist[j]=INF; memset(hash,0,sizeof(hash)); dist[i]=0; hash[i]=1; q.push(i); while( !q.empty() ) { now = q.front(); q.pop(); hash[now]=false; for( k = 2 ; k <= biao[now][0].zhi ; k++ ) { t = biao[now][k].shunxu; if( dist[t] > dist[now] + biao[now][k].zhi ) { dist[t] = dist[now] + biao[now][k].zhi; if(!hash[t]) { hash[t]=true; q.push(t); } } } } for(j=1;j<=secs;j++) if(dist[j]>nearest[j]) dist[j]=nearest[j]; for(j=1,maxx=-1;j<=secs;j++) if(dist[j]>maxx) maxx=dist[j]; if(maxx<max) { max=maxx; final=i; } } printf("%d/n",final); } return 0; }
堆优化+邻接表,搞了好长时间。。。。。
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> struct node { int value; int order; struct node *next; } temp,queue[510]; struct node *biao[501],*nownow,space[100000]; const int INF=9999999; int edge[501][501]; int nearest[501]; int hash[501]; int dist[501],loca[101]; int station,secs,r,pre,i,j,k,flag,final; int from,to,weight,maxx,t,spacestart,now; int inqueue[510]; char a[100]; void minheapify(struct node *a,int i) { int mm,l = i << 1; int r = l + 1; int largest = i; struct node temp; if( l <= a[0].value && a[l].value < a[largest].value) largest = l; if( r <= a[0].value && a[r].value < a[largest].value) largest = r; if( largest != i) { temp = a[i];a[i] = a[largest];a[largest] = temp; mm = inqueue[ a[i].order ]; inqueue[ a[i].order ] = inqueue[ a[largest].order ]; inqueue[ a[largest].order ] = mm; minheapify(a,largest); } } struct node pop(struct node *a) { struct node max = a[1]; a[1] = a[ a[0].value ]; a[0].value--; minheapify(a,1); return max; } void insert(struct node *a,struct node k,int i) { int t,mm; struct node temp; a[i] = k; inqueue[ k.order ] = i; while( i>1 && a[t = i >> 1].value > a[i].value ) { temp = a[i];a[i] = a[t];a[t] = temp; mm = inqueue[ a[i].order ]; inqueue[ a[i].order ] = inqueue[ a[t].order ]; inqueue[ a[t].order ] = mm; i = t; } } void push(struct node *a,struct node k) { a[0].value ++; insert(a,k,a[0].value); } void dijkstra(int i) { memset(dist,INF,sizeof(dist)); memset(hash,0,sizeof(hash)); memset(inqueue,0,sizeof(inqueue)); dist[now=i]=0;hash[i]=1; queue[0].value = 0; inqueue[i] = 1; for(j=1;j<secs;j++) { nownow = biao[now]; while( nownow != NULL ) { k = nownow->order; if(hash[k]==0 && dist[k]>dist[now]+nownow->value) { temp.value=dist[temp.order=k]=dist[now]+nownow->value; if(!inqueue[k]) push(queue,temp); else insert(queue,temp,inqueue[k]); } nownow = nownow->next; } temp = pop(queue); now = temp.order; hash[now]=1; } } int main(void) { freopen("b.in","r",stdin); freopen("out.txt","w",stdout); int max,min; while(gets(a)!=NULL) { sscanf(a,"%d%d",&station,&secs); for(i=1;i<=secs;i++) for(j=1;j<=secs;j++) edge[i][j]=INF; if(secs==1 && station) { printf("1/n");gets(a);gets(a); continue; } for(i=1;i<=station;i++) scanf("%d",&loca[i]); getchar(); for(i=0;i<=500;i++) biao[i] = NULL; spacestart=0; while( gets(a)!=NULL && strlen(a)!=0) { sscanf(a,"%d%d%d",&from,&to,&weight); i=2; while(i--) { spacestart++; space[spacestart].next=biao[from]; biao[from]=&space[spacestart]; space[spacestart].value=weight; space[spacestart].order=to; t = from; from = to; to = t; } } memset(nearest,INF,sizeof(nearest)); for(i=1;i<=station;i++) { dijkstra(loca[i]); for(j=1;j<=secs;j++) if(nearest[j]>dist[j]) nearest[j]=dist[j]; } for(i=1,max=-1;i<=secs;i++) if(nearest[i]>max) max=nearest[i]; for(i=1;i<=secs;i++) { if(nearest[i]==0) continue; dijkstra(i); for(j=1;j<=secs;j++) if(dist[j]>nearest[j]) dist[j]=nearest[j]; for(j=1,maxx=-1;j<=secs;j++) if(dist[j]>maxx) maxx=dist[j]; if(maxx<max) {max=maxx;final=i;} } printf("%d/n",final); } return 0; }