1、不知道是UVa的题太难了还是我太弱了,这道题写了三个多小时。终于学会了用优先队列来优化的dijkstra以及前向星表示法。
2、我是这么做的:对每一对结点(楼层),记录四个信息,始发点,终点,时间,电梯类型。注意每一对都要,而不是仅仅是楼层相连的需要。否则在加60的时候会遇到麻烦,dijkstra说到底是用的贪心,如果仅仅记录相连的楼层的话,可能会漏掉一些方案(目光短浅)。我举个例子,如0到1楼是乘坐1号电梯,1到2楼用1号电梯花费是10,2到3楼用1号花费是1000,1到2楼用2号电梯花费是1,2到3楼用2号花费是1,这样在做最初的决策的时候,由于从1到2楼如果换乘2号电梯的话,会额外花费60的费用,所以这条路就不可能再走了,但是它看不到2到3楼有1000的花费在等着。所以说贪心是短视的。
3、后来还是一直过不了第二个样例,我才发现是数组开小了,前向星表示法,first数组记录第一个边的编号,它的元素个数等于结点数,next数组记录某个边的下一个边的编号,它的元素个数等于边的数目。
4、交上去一次AC,还是挺值得高兴的。
int a[100];int n,k,cnt;
priority_queue<point,vector<point>,cmp>q;
void init(){
for(int i=0;i<n;i++)
scanf("%d",&cost[i]);
for(int i=0;i<MAXN;i++)
d[i]=(i==0?0:INF);
for(int i=0;i<n;i++){
int temp,N=0;
char ch;
while(scanf("%d",&temp)==1){
a[N++]=temp;
if((ch=getchar())=='\n') break;
}
for(int j=0;j<N-1;j++){
for(int h=j+1;h<N;h++){
int num=abs(a[h]-a[j])*cost[i];
e[cnt].u=a[j];e[cnt].v=a[h];e[cnt].w=num;e[cnt].type=i;
e[cnt+1].u=a[h];e[cnt+1].v=a[j];e[cnt+1].w=num;e[cnt+1].type=i;
cnt+=2;
}
}
}
return;
}
int main(){
//freopen("lift.in","r",stdin);
//freopen("lift.out","w",stdout);
while(scanf("%d%d",&n,&k)==2){
cnt=0;
init();
for(int i=0;i<MAXN;i++) first[i]=-1;
for(int j=0;j<cnt;j++){
next[j]=first[e[j].u];
first[e[j].u]=j;
}
memset(done,0,sizeof(done));
q.push(point(d[0],0,-1));
while(!q.empty()){
point u=q.top();q.pop();
int x=u.num;
if(done[x]) continue;
done[x]=true;
int plus;
for(int i=first[x];i!=-1;i=next[i]){
if(e[i].type==u.type||u.type==-1) plus=0;
else plus=60;
if(d[e[i].v]>d[x]+e[i].w+plus){
d[e[i].v]=d[x]+e[i].w+plus;
q.push(point(d[e[i].v],e[i].v,e[i].type));
}
}
}
if(d[k]!=INF)
printf("%d\n",d[k]);
else printf("IMPOSSIBLE\n");
}
return 0;
}