SGU 103 Traffic Lights 最短路

11 篇文章 0 订阅

       n个点,m条边,给起点和终点,求起点到终点的最小花费,每个点都有两种状态,每个点的每种状态都有一个持续的时间,只有在某条边连接的两个点状态相同时这条边才可走。实际上就是一个带限制的最短路,每次松弛的时候,花费就是边的花费加上最少要等多长时间两个点的颜色会变成相同..如果永远无法相同,这条边就不能走了...思路很简单,时间的处理写起来比较恶心....

       

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int inf=(1<<28);
const int maxn=330;
int n,m,tt,p;
int st,ed;

struct EDGE
{
    int v,w,next;
}edge[30000];
int g[maxn];
int ne;

struct Light
{
    bool type;
    int res,t1,t2;
}light[maxn];
int pre[maxn];
bool vis[maxn];
int dis[maxn];
int slove(int src)
{
    memset(vis,false,sizeof vis);
    memset(pre,0,sizeof pre);
    for (int i=0; i<=n; i++) dis[i]=inf;
    dis[src]=0;
    queue<int>q;
    q.push(src);
    vis[src]=true;

    while(!q.empty())
    {
        int u,v;
        int t1,t2;
        bool f1,f2;
        u=q.front();
        int now=dis[u];
        int cost=0;
        q.pop();
        vis[u]=false;
        for(int j=g[u]; j!=-1; j=edge[j].next)
        {
            v=edge[j].v;
            cost=edge[j].w;
            t1=now-light[u].res;
            if (t1<0) f1=light[u].type,t1=light[u].res-now;
            else {
                t1=t1 % (light[u].t1+light[u].t2);
                if (!light[u].type)
                {
                   if (t1>=light[u].t2) f1=0,t1=light[u].t1+light[u].t2-t1;
                   else f1=1,t1=light[u].t2-t1;
                }
                else
                {
                   if (t1>=light[u].t1) f1=1,t1=light[u].t1+light[u].t2-t1;
                   else f1=0,t1=light[u].t1-t1;
                }
            }
            t2=now-light[v].res;
            if (t2<0) f2=light[v].type,t2=light[v].res-now;
            else
            {
                t2=t2 % (light[v].t1+light[v].t2);
                if (!light[v].type)
                {
                    if (t2>=light[v].t2) f2=0,t2=light[v].t1+light[v].t2-t2;
                    else f2=1,t2=light[v].t2-t2;
                }
                else
                {
                    if (t2>=light[v].t1) f2=1,t2=light[v].t1+light[v].t2-t2;
                    else f2=0,t2=light[v].t1-t2;
                }
            }
            if (f1==f2)
            {
                if (dis[v]>cost+dis[u])
                {
                    dis[v]=dis[u]+cost;
                    pre[v]=u;
                    if (!vis[v]){
                    q.push(v);
                    vis[v]=true;
                    }
                }
            }
            else
            {
                bool ok=true;
                if (t1!=t2) cost+=min(t1,t2);
                else
                {
                    f1^=1;
                    f2^=1;
                    cost+=t1;

                    if (!f1) t1=light[u].t1;
                    else t1=light[u].t2;

                    if (!f2) t2=light[v].t1;
                    else t2=light[v].t2;

                    if (t1!=t2) cost+=min(t1,t2);
                    else
                    {
                        f1^=1;
                        f2^=1;
                        cost+=t1;
                        if (!f1) t1=light[u].t1;
                        else t1=light[u].t2;

                        if (!f2) t2=light[v].t1;
                        else t2=light[v].t2;

                        if (t1!=t2) cost+=min(t1,t2);
                        else ok=false;
                    }
                }
                if (ok)
                {
                    if (dis[v]>dis[u]+cost)
                    {
                        dis[v]=dis[u]+cost;
                        pre[v]=u;
                        if (!vis[v])
                        {
                            q.push(v);
                            vis[v]=true;
                        }
                    }
                }
            }
        }

    }
    return dis[ed];
}
void find(int u)
{
    if (u==0) return;
    find(pre[u]);
    if (u==st)
    printf("%d",u);
    else printf(" %d",u);
}
int main()
{
//    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&st,&ed))
    {
        scanf("%d%d",&n,&m);
        char s[5];
        for (int i=1; i<=n; i++)
        {
            scanf("%s",&s);
            light[i].type=(s[0]=='P');
            scanf("%d%d%d",&light[i].res,&light[i].t1,&light[i].t2);
        }
        ne=0;
        int x,y,z;
        memset(g,-1,sizeof g);

        for (int i=1; i<=m; i++)
        {
           scanf("%d%d%d",&x,&y,&z);
           edge[ne].v=y;
           edge[ne].next=g[x];
           edge[ne].w=z;
           g[x]=ne;
           ne++;
           edge[ne].v=x;
           edge[ne].next=g[y];
           edge[ne].w=z;
           g[y]=ne;
           ne++;
        }
        int out=slove(st);
        if (out<inf)
        {
        printf("%d\n",out);
        find(ed);
         printf("\n");
        }
        else puts("0");
    }

    return 0;
}


      

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值