SGU103+POJ 1158 最短路/dp

题意:一个无向图,求起点到终点最少时间,限制:每个路口有灯,要灯颜色一样才能过去,灯之有俩种颜色,周期
变化,给定每个灯初态,时间。
思路:开始就想到直接DP,方程dp[k]=dp[i]+distance[i][k]+waittime(i,k),于是天真得BFS敲了这个,
SB啊!有些点松弛了,之后它又被松弛,它便还可以松弛别人啊!否则世界上最短路O(n)的算法就诞生了!
所以,一旦某个点被松弛了,它便可以再入队,啊哈?这不就是SPFA吗!!我去,这次是对SPFA更加理解了,
自己想法竟然遇上经典算法了。其本质就是DP,状态的转移,初期放的错误是:没有所有点都对k松弛,而k已经出队
(对别人松弛过了)。
这题较麻烦的地方是计算等待的时间,细节模拟,我是先算出当前时间,路口的状态,再讨论下接下来等待的
时间。
未1A:
复制差不多代码的时候2个数据没有改,导致错误。打印路劲的时候开始用栈(因为记录是逆序的)。导致爆内存,
以后尽量不要用栈记录!
改进:其实写等待函数可以分俩个函数,每个点当前状态一个,加一个算时间的函数。那样代码就减少很多,

并且也清晰很多。


#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
struct nodes
{
    int remain;
    char initial;
    int tb;
    int tp;
};
nodes node[310];
int n,m;int s,l;
int times=0;
int e[50000][3];int head[310];int nume=0;
void inline addedge(int from,int to, int w)
{
    e[nume][0]=to;e[nume][1]=head[from];head[from]=nume;
    e[nume++][2]=w;
    e[nume][0]=from;e[nume][1]=head[to];head[to]=nume;
    e[nume++][2]=w;
}
int dp[310];
void readin()
{
    cin>>s>>l>>n>>m;
   for(int i=1;i<=n;i++)
   {
       head[i]=-1;
       dp[i]=inf;
       cin>>node[i].initial>>node[i].remain>>node[i].tb>>node[i].tp;
   }
   int from,to,w;
   for(int i=0;i<m;i++)
   {
       cin>>from>>to>>w;
       addedge(from,to,w);
   }
}
char inline change(char s)  //变色
{
    if(s=='B')return 'P';
    return 'B';
}
int gettime(int nowt,int u,int v) //计算等待时间
{
    int reu=0,rev=0;               //模拟出当前灯还剩余多少时间
    int nowu=nowt-node[u].remain;  //先减去开始的剩余时间
    char cv=node[v].initial,cu=node[u].initial;//cu,cv模拟出当前灯
    if(nowu==0)         //干好
    {
        if(node[u].initial=='B'){cu='p';reu=node[u].tp;}
        else {cu='B';reu=node[u].tb;}
    }
    else if(nowu<0)   //剩余时间还有
    {
        reu=node[u].remain-nowt;
    }
    else                 
    {
        int re=nowu%(node[u].tb+node[u].tp);//多余
        if(re==0)cu=change(cu);         //讨论略繁琐
        else if(cu=='B')
        {
              if(re<node[u].tp)
                 cu=change(cu);
        }
        else if(cu=='P')
        {
            if(re<node[u].tb)
                cu=change(cu);
        }
        if(cu=='P')
        {
            reu=(node[u].tb+node[u].tp)-re-node[u].tb;
            if(node[u].initial=='P')reu+=node[u].tb;
        }
        else if(cu=='B')
        {
            reu=(node[u].tb+node[u].tp)-re-node[u].tp;
            if(node[u].initial=='B')reu+=node[u].tp;
        }
    }
     int nowv=nowt-node[v].remain;
    if(nowv==0)
    {
        if(node[v].initial=='B'){cv='p';rev=node[v].tp;}
        else {cv='B';rev=node[v].tb;}
    }
    else if(nowv<0)
    {
        rev=-nowv;
    }
     else
    {
        int re=nowv%(node[v].tb+node[v].tp);
        if(re==0)cv=change(cv);
        else if(cv=='B')
        {
              if(re<node[v].tp)
                 cv=change(cv);
        }
        else if(cv=='P')
        {
            if(re<node[v].tb)
              cv=change(cv);
        }
          if(cv=='P')
        {
            rev=(node[v].tb+node[v].tp)-re-node[v].tb;
            if(node[v].initial=='P')rev+=node[v].tb;
        }
        else if(cv=='B')
        {
            rev=(node[v].tb+node[v].tp)-re-node[v].tp;
            if(node[v].initial=='B')rev+=node[v].tp;
        }
    }
    if(cu==cv)return 0;
    else
    {
          if(reu>rev)
              return rev;
          if(reu<rev)
              return reu;
          else
           {
               cu=change(cu);
               cv=change(cv);
               if(cu=='B')
               {
                   if(node[u].tb<node[v].tp)
                       return reu+node[u].tb;
                   else if(node[u].tb>node[v].tp)
                       return reu+node[v].tp;
                   else
                      {
                          if(node[u].tp<node[v].tb)
                               return reu+node[u].tb+node[u].tp;
                          else if(node[u].tp>node[v].tb)
                              return reu+node[v].tp+node[v].tb;
                          else
                              return   inf;
                      }
               }
                else if(cu=='P')
               {
                   if(node[u].tp<node[v].tb)
                       return reu+node[u].tp;
                   else if(node[u].tp>node[v].tb)
                       return reu+node[v].tb;
                   else
                      {
                          if(node[u].tb<node[v].tp)
                               return reu+node[u].tp+node[u].tb;
                          else if(node[u].tb>node[v].tp)
                              return reu+node[v].tb+node[v].tp;
                          else
                              return   inf;
                      }
               }
           }
    }
}
int vis[310];
int fa[310];
int way[310];
queue<int>q;
int main()
{
    readin();
    q.push(s);
    dp[s]=0;
    while(!q.empty())         //spfa
    { 
        int cur=q.front();
        q.pop();
        vis[cur]=0;
        for(int i=head[cur];i!=-1;i=e[i][1])
        {
            int v=e[i][0];
            int getv=dp[cur]+e[i][2];
            getv+=gettime(dp[cur],cur,v);
            if(vis[v]==0&&getv<dp[v])
              {
                  q.push(v);
                  vis[v]=1;
              }
            if(getv<inf&&getv<dp[v])
            {
                dp[v]=getv;
                fa[v]=cur;  //跟新时候记录父节点,不可记录子节点法,容易想到反例。
            }
        }
    }
    if(dp[l]>=inf){cout<<0<<endl;return 0;}  //无解
    cout<<dp[l]<<endl;
    int i=l;
    int num=0;
    while(i!=s)
    {
       way[num++]=i;
        i=fa[i];
    }
    way[num]=i;
    for(int j=num;j>=0;j--)
    {
        if(j==0)printf("%d\n",way[j]);
        else printf("%d ",way[j]);
    }
 return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值