[POJ] 3539 Elevator

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

给定一个电梯,可以上升a,b,c层和回到1层,给定楼高h,求可达层数

 

lyd讲的同余类BFS,方法是先把三个量压成两个,即把h%a,因为对于一个x∈{h%a},若x可达,则x+ak一定可达。

然后考虑在这个模a的剩余系中,b和c的情况。

从1开始连边,从点i连向(i+w)%a,代价为w,其中w为b或c。

意义就是,对于一个楼层x,从x到达最近x+w层的代价为w,这很显然。

从1开始做单源最短路,然后只需要统计dis小于等于h的,大于的显然不可达了。

因为是在模a剩余系下做的,所以对于一个满足dis[u]<=h的u,它是一个剩余系的代表元,要算出剩余系大小。

 

//drunk,fix later
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>

using namespace std;

typedef long long ll;

const int MAXN=100005;

struct Edge{
  int next,to;
  ll w;
}e[MAXN<<2];
int ecnt,head[MAXN];
inline void add(int x,int y,ll w){
  e[++ecnt].next = head[x];
  e[ecnt].to = y;
  e[ecnt].w = w;
  head[x] = ecnt;
}

ll h,a,b,c;

queue<int> Q;
int inq[MAXN];
ll dis[MAXN];
void spfa(){
  for(int i=0;i<=a;i++) dis[i]=1ll<<60;
  Q.push(1);inq[1]=1;dis[1]=1;
  while(!Q.empty()){
    int top=Q.front();Q.pop();inq[top]=0;
    for(int i=head[top];i;i=e[i].next){
      int v=e[i].to;
      if(dis[v]>dis[top]+e[i].w){
        dis[v]=dis[top]+e[i].w;
        if(!inq[v]) Q.push(v),inq[v]=1;
      }
    }
  }
}

int main(){
  cin>>h>>a>>b>>c;
  if(a>b) swap(a,b);
  if(a>c) swap(a,c);
  if(a==1) return cout<<h,0;
  for(int i=0;i<a;i++){
    add(i,(i+b)%a,b);
    add(i,(i+c)%a,c);
  }
  ll sum=0;
  spfa();
  for(int i=0;i<a;i++) if(dis[i]<=h) sum+=(ll)(h-dis[i])/a+1;
  cout<<sum;
  return 0;
}

 

posted @ 2018-07-08 20:18  GhostCai  阅读(121)  评论(0编辑  收藏  举报