URAL 1905 Travel in Time BFS(广度搜索)

在无限失败中获得成功,什么wrong,什么TLE,什么RE都出现过,错了几十次的说。。


现在在这里说明下我的理解。。不知道有没错误。。

题意:这是关于时空穿梭的图论题?题目告诉我们n个星球,m个路径,每条路径有起点,终点,起始时间,终结时间;最后一行是开始地点,目的地,开始时间和叛徒所在时间。当然我就这么理解了,英语四级425的货,没办法理解具体单词。。这题的特色就是时间可以倒流,十分幻想啊(''),而且人物不能再相同地点和相同时间下出现。

解法:bfs的结果,当直接来会TLE啊,RE啊,(ˇˍˇ) 我就是这样过来的。主要缩减的地方是在A时刻到达C地点的时候,开车时间B(B>=A)的路线肯定可以过去,可以每条路在BFS中只用去一遍,排序后省略遍历这部分,这里就能缩减遍历的时间,具体在代码中指出。还有就是我没用vector来存路径,不知道有没效果的说大笑,一开始存vector的时候RE了。


代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <map>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
struct node{
    int from,to;
    int t1,t2;
    int num;
}e[maxn];
int end_where,end_time,start_where,start_time,sum;
int first[maxn],last[maxn],pre[maxn],mark[maxn];

int cmp(node a,node b)
{
    if(a.from==b.from)return a.t1>b.t1;//开车时间从大到小排序下
    return a.from<b.from;
}
void show(int a)//递归输出结果
{
    sum++;
    if(pre[a]==-1)
    {
        printf("%d\n",sum);
        printf("%d",a);
        return;
    }
    show(pre[a]);
    printf(" %d",a);
}

void bfs(int m)
{
    queue<int>q;
    int i,j,k,v;
    q.push(m);//队列里加的是序号,应该能简约点空间吧,maybe
    mark[m]=1;
    while(!q.empty())
    {
        v=q.front();
        q.pop();
        for(i=first[e[v].to];i<last[e[v].to];i++)
        {
            if(mark[i])continue;
            if(e[v].t2>e[i].t1){first[e[v].to]=i;break;}//排序过之后,后面的必定不符合,开始点也变换成这点
            mark[i]=1;
            pre[e[i].num]=e[v].num;//记录路径
            if(e[i].to==end_where&&e[i].t2<=end_time)
            {
                sum=0;
                show(e[i].num);
                printf("\n");
                return;
            }
            q.push(i);
        }
    }
    printf("Impossible\n");
}
int main()
{
    //freopen("D:\\output.txt","r",stdin);
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j,k;
        memset(first,0,sizeof(first));
        memset(last,0,sizeof(last));
        memset(mark,0,sizeof(mark));
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d%d",&e[i].from,&e[i].to,&e[i].t1,&e[i].t2);
            e[i].num=i+1;
        }
        scanf("%d%d%d%d",&start_where,&end_where,&start_time,&end_time);
        if(start_where==end_where&&start_time<=end_time){printf("0\n");continue;}

        sort(e,e+m,cmp);//先起点排序,之后根据开车时间排序
        for(i=0;i<m;i++)
        {
            if(i==0||e[i].from!=e[i-1].from)first[e[i].from]=i;     //起点在e[i].from的段,在[first[e[i].from],last[e[i].from])间
            if(i==m-1||e[i].from!=e[i+1].from)last[e[i].from]=i+1;
        }
        e[m].to=start_where;
        e[m].t2=start_time;
        e[m].num=-1;
        bfs(m);
    }
    return 0;
}
/*
3 3
1 2 10 20
3 2 11 19
1 3 11 10
1 2 10 19

3 3
1 2 20 10
2 1 30 10
1 3 40 30
1 3 10 30

2 2
1 1 30 10
1 2 20 10
1 2 30 10

3 3
1 2 20 10
2 1 10 15
1 3 15 10
1 3 20 10

3 5
1 2 10 20
2 1 20 10
1 2 10 20
2 1 20 10
1 3 10 30
1 3 10 30

3 3
1 2 10 20
2 1 20 5
1 3 10 30
1 3 10 30
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值