UVa1599/poj 3967 Ideal Path

        题意:一个连通的带权(权表示的不是距离,相邻点距离为1)无向图,有n个点,m条边,从点1走到点n,求最短路径,如果有多条路径最短,输出权的字典序最小的路径。

        思路:先倒着BFS一次,记录每个点到终点的距离,然后正向BFS,每一步走到的点,距离应该比上一步少1。枚举满足上述条件的点,找出全最小的那个(些)点进行扩展。

        这题我WA,RE,TLE了好几页,血的教训啊。。。因为题目数据量大,我没用STL,手写的队列和链表,需要为队列开空间。然后我在第二次BFS时没有检查入队的元素是否已在队列中,爆队了。。可是poj返回的是WA,害我一直在找其他的原因,然后我用其他语言提交,发现变成了RE,把队列开大变成TLE。。。最后才发现问题的原因。。


#include <iostream>             
#include <stdio.h>             
#include <cmath>             
#include <algorithm>             
#include <iomanip>             
#include <cstdlib>             
#include <string>             
#include <string.h>             
#include <vector>             
#include <queue>             
#include <stack>             
#include <map>           
#include <set>           
#include <ctype.h>             
#define INF 1<<30         
#define ll long long         
#define max3(a,b,c) max(a,max(b,c))         
#define MAXN 1000    
    
using namespace std;    
    
struct edge{    
    int v;    
    int c;    
};    
  
edge eg[410000];
int head[410000];  
int next[410000];
int level[110000];
int tmp[410000];
bool vis[110000];    
int minc[110000]; 
int Q[410000];

int main(){
    int n,m;    
    while(~scanf("%d%d",&n,&m)){        
        int front=0;  
        int rear=0;  
        memset(level,0,sizeof(level));    
        memset(head,-1,sizeof(head));  
        memset(next,-1,sizeof(next));  
        memset(vis,0,sizeof(vis));    
        for(int i=0;i<=n;i++)minc[i]=INF;  
          
        for(int i=1;i<=m;i++){    
            int u,v,c;    
            scanf("%d%d%d",&u,&v,&c);    
            int h;  
              
            eg[i*2-1].v=v; eg[i*2-1].c=c;   
            next[i*2-1]=head[u];  
            head[u]=i*2-1;  
              
              
            eg[i*2].v=u; eg[i*2].c=c;    
            next[i*2]=head[v];  
            head[v]=i*2;  
              
        }  
		   
        Q[rear++]=n;  
        level[n]=1;    
        vis[n]=1;  
        while(front!=rear){      
            int cur=Q[front]; front++;    
            int t=head[cur];  
            while(t!=-1){    
                int v=eg[t].v;    
                if( !vis[v]){    
                    level[v]=level[cur]+1;     
                    Q[rear++]=v;  
                    vis[v]=1;    
                }    
                t=next[t];  
            }    
        }
        
		memset(vis,0,sizeof(vis)); 
        int test=rear;  
        front=rear=0;  
        Q[rear++]=1;  
        int k=level[1];  
        for(int i=k;i>1;i--){  
            int end=0;  
            while(front!=rear){    
                int cur=Q[front]; front++;  
                tmp[end++]=cur;  
            }  
            for(int j=0;j<end;j++){  
                int cur=tmp[j];  
                int t=head[cur];   
                while(t!=-1){  
                    int v=eg[t].v;  
                    if( !vis[v]&&level[v]==i-1 && eg[t].c<minc[i-1]  ){    
                        minc[i-1]= eg[t].c;    
                    }    
                    t=next[t];  
                }  
            }  
              
            for(int j=0;j<end;j++){  
                int cur=tmp[j];  
                int t=head[cur];   
                while(t!=-1){  
                    int v=eg[t].v;  
                    if( !vis[v]&&level[v]==i-1 && eg[t].c==minc[i-1]  ){    
                        vis[v]=1;
                        Q[rear++]=v;  
                    }   
                    t=next[t];  
                }  
            }  
        }  
          
        printf("%d\n",level[1]-1);    
        for(int i=k-1;i>=1;i--){  
            printf("%d",minc[i]);  
            if(i!=1)printf(" ");  
        }  
        printf("\n");  
    }    
    return 0;    
}    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值