• Traffic Lights


    题目大意:有一个城市的路线图,有N个交叉点,每两个交叉点之间只有一条路,现在想从交点u去交点v,不过这个路的交通比较特别,每个路都有一个交通灯,灯有两种颜色,蓝色和紫色,例如一条路线在交点s,t之间,如果想从s走到t,那么只有等s和t的交通灯的颜色一致的时候才可以从s走,求出来从u到v的最短时间。

    分析:比较明显能看出来是一个最短路问题,不过里面夹杂的这个交通灯比较恶心,要随时能求出来两点点下一个相同颜色的时间,如果使用时间去枚举无疑是个比较笨的方法,注意到有个剩余时间,并且交通灯的每种颜色存在的最大值是100,所以可以判断出,一定会有重复情况出现,比如s剩余a,t剩余b,这种状态再次出现不会超过200次蓝紫灯循环,所以只需要枚举200次即可,如果还是找不带相同颜色,那么就说明这条路不能行走。ps.时间内存都比较小,边数比较多,所以邻接矩阵比连接表更省内存,注意有可能会有重边的情况。

    代码如下:

    =========================================================================================================================

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int MAXN = 307;
    const int oo = 1e9+7;
    
    struct Junction
    {
        int op;///等于0是B, 等于1代表P
        int Last;///剩余时间
        int t[2];///两种灯的转换时间
    
        Junction NewOp(int time)
        {///time时刻的状态
            Junction res;
            if(time >= Last)
            {///当前时间大于剩余时间,等于的时候也需要转变成下一个灯
                time -= Last;
                time %= (t[0]+t[1]);
    
                if(time >= t[op^1])
                {
                    res.op = op;
                    res.Last = t[op] - (time-t[op^1]);
                }
                else
                {
                    res.op = op^1;
                    res.Last = t[op^1]-time;
                }
            }
            else
            {
                res.op = op;
                res.Last = Last - time;
            }
    
            res.t[0] = t[0], res.t[1] = t[1];
    
            return res;
        }
        int SameColor(Junction a, Junction b)
        {///两个路灯下个相同颜色最少需要时间,-1表示不可能相同
         ///因为中间涉及到值得改变,所以不使用指针
            int i, time=0;
    
            for(i=0; i<200; i++)
            {
                if(a.op == b.op)
                    return time;
                else if(a.Last >= b.Last)
                {
                    time += b.Last;
                    a.Last -= b.Last;
                    b.Last = 0;
                }
                else if(a.Last < b.Last)
                {
                    time += a.Last;
                    b.Last -= a.Last;
                    a.Last = 0;
                }
    
                if(a.Last == 0)
                {
                    a.op ^= 1;
                    a.Last = a.t[a.op];
                }
                if(b.Last == 0)
                {
                    b.op ^= 1;
                    b.Last = b.t[b.op];
                }
            }
    
            return -1;
        }
    };
    
    Junction p[MAXN];///交叉点
    int N;///交叉点个数
    int G[MAXN][MAXN];
    
    void Dij(int start, int end)
    {
        int dist[MAXN], path[MAXN]={0};
        int visit[MAXN]={0};
    
        for(int i=1; i<=N; i++)
            dist[i] = oo;
        dist[start] = 0;
    
        for(int t=0; t<N; t++)
        {
            int index=start, Min=oo;
    
            for(int i=1; i<=N; i++)
            {
                if(visit[i] == false && dist[i] < Min)
                {
                    Min = dist[i];
                    index = i;
                }
            }
    
            if(visit[index])
                break;
            visit[index] = true;
    
            Junction u = p[index].NewOp(dist[index]), v;
    
            for(int i=1; i<=N; i++)
            {
                if(!visit[i] && G[index][i] != oo && dist[i]>dist[index]+G[index][i])
                {
                    v = p[i].NewOp(dist[index]);
                    int time = u.SameColor(u, v);
    
                    if(time != -1 && dist[i] > dist[index]+G[index][i]+time)
                    {
                        dist[i] = dist[index] + G[index][i] + time;
                        path[i] = index;
                    }
                }
            }
        }
    
        if(dist[end] == oo)
            printf("0
    ");
        else
        {
            printf("%d
    ", dist[end]);
    
            int k=0, ans[MAXN];
    
            while(end)
            {
                ans[k++] = end;
                end = path[end];
            }
    
            for(int i=k-1; i>=0; i--)
                printf("%d%c", ans[i], i==0?'
    ':' ');
        }
    }
    
    int main()
    {
        int M, start, end;
        char s[10];
    
        scanf("%d%d%d%d", &start, &end, &N, &M);
    
        for(int i=1; i<=N; i++)
        {
            scanf("%s%d%d%d", s, &p[i].Last, &p[i].t[0], &p[i].t[1]);
            p[i].op = (s[0]=='B' ? 0 : 1);
        }
    
        int u, v, len;
    
        for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
            G[i][j] = oo;
    
        while(M--)
        {
            scanf("%d%d%d", &u, &v, &len);
            G[u][v] = G[v][u] = min(G[u][v], len);
        }
    
        Dij(start, end);
    
        return 0;
    }
  • 相关阅读:
    犯错记录(一)
    BullseyeCoverage:代码覆盖率。
    测试工具:insure++
    C++ 常见容器
    linux修改rm指令执行(数据安全)
    C++细节系列(零):零散记录
    vim中使用gdb。
    vim自动补全文章搜集
    排序算法的个人心得体会。
    面向对象的三个特征。
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4803450.html
Copyright © 2020-2023  润新知