poj 3539 Elevator——同余类bfs

题目:http://poj.org/problem?id=3539

考虑把层数分为模a剩余系。同类内可通过+若干个a走到。

不同类之间需要通过+b、+c来走到。

需要求出每一类中最小的能走到的。即最短路。

注意memset成0x3f!不要直接memset成1!

  仔细一看,long long下赋1是17位,赋0x3f是19位。而h是18位。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=1e5+5;
ll h,dis[N],ans;
int a,b,c,head[N],xnt;
bool vis[N];
struct Ed{
  int next,to,w;
  Ed(int n=0,int t=0,int z=0):next(n),to(t),w(z) {}
}ed[N<<1];
void dj()
{
  memset(dis,0x3f,sizeof dis);dis[1%a]=1;//%a //0x3f
  priority_queue<pair<ll,int> > q;
  q.push(make_pair(-1,1%a));
  while(q.size())
    {
      int k=q.top().second;q.pop();
      while(q.size()&&vis[k])k=q.top().second,q.pop();
      if(vis[k])break;vis[k]=1;
      for(int i=head[k],v;i;i=ed[i].next)
    if(dis[k]+ed[i].w<dis[v=ed[i].to])
      {
        dis[v]=dis[k]+ed[i].w;q.push(make_pair(-dis[v],v));
      }
    }
}
int main()
{
  scanf("%lld%d%d%d",&h,&a,&b,&c);
  for(int i=0;i<a;i++)
    {
      ed[++xnt]=Ed(head[i],(i+b)%a,b);head[i]=xnt;
      ed[++xnt]=Ed(head[i],(i+c)%a,c);head[i]=xnt;
    }
  dj();
  for(int i=0;i<a;i++)if(dis[i]<=h)ans+=(h-dis[i])/a+1;//<=h
  printf("%lld",ans);
  return 0;
}
dj

再来个跑得快的(spfa)。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e5+5;
ll ans,h,dis[N];
int a,b,c,q[N<<4],hd,tl;
bool vis[N];
int main()
{
  scanf("%lld%d%d%d",&h,&a,&b,&c);
  if(a<b)swap(a,b);if(a<c)swap(a,c);
  memset(dis,0x3f,sizeof dis);dis[1%a]=1;
  hd=1;q[++tl]=1;vis[1%a]=1;
  while(hd<=tl)
    {
      int k=q[hd++];vis[k]=0;
      if(dis[(k+b)%a]>dis[k]+b)
    {
      dis[(k+b)%a]=dis[k]+b;
      if(!vis[(k+b)%a])q[++tl]=(k+b)%a,vis[(k+b)%a]=1;
    }
      if(dis[(k+c)%a]>dis[k]+c)
    {
      dis[(k+c)%a]=dis[k]+c;
      if(!vis[(k+c)%a])q[++tl]=(k+c)%a,vis[(k+c)%a]=1;
    }
    }
  for(int i=0;i<a;i++)if(dis[i]<=h)ans+=(h-dis[i])/a+1;
  printf("%lld",ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9275440.html