Codeforces483Div1 983C Elevator

该博客探讨了Codeforces483Div1 983C Elevator问题,即在9层大楼中,如何通过控制电梯运行,使得所有人在不超过4人同时在电梯内的限制下,以最小的总时间到达目的地。作者提出使用状压DP的方法解决,通过优化减少状态空间,将原本可能超时的2×10^8复杂度降低到2×10^7,确保算法的可行性。转移策略虽未详述,但强调其简单暴力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

在一个9层的大楼内(大河内一*?),只有一台电梯,现在有N个人按顺序要乘电梯去他们想去的楼层,且不到达他们的目的地他们是不会下电梯的,要求每时每刻电梯内最多有4人,且上电梯的顺序必须严格按照人到达的顺序。但下电梯的顺序是任意的。每个人上、下电梯均需要1s,电梯移动一层也需要1s。现在求如何控制电梯,使得让所有人到达目的地的时间总和尽量小?
N2000N≤2000


分析:

据说这道题还有最短路做法。。。不过我没去研究,就写一下考场上的做法吧:
考虑到数据范围极其小,很容易想到状压DP,
DP[i][j][k]DP[i][j][k]表示前i个人已经上过电梯,现在电梯内的人目的地状态为j(4位10进制数,0表示没有人),电梯目前在k层。
粗略算一下复杂度:2000×104×10=2×1082000×104×10=2×108估计要炸。
考虑优化一维,很显然,如果电梯是满员,那么必然会直接找一个位置让人下电梯(不能再上人了),那么这种情况不需要特别写一个状态来保存,每次转移后满员时,直接枚举停的位置,让某个人下电梯,这样一来又转移到3个人的状态。所以复杂度为2000×103×10=21072000×103×10=2∗107就没什么大问题了。
转移很暴力很简单,这里就不细说了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 2010
#define MAXM 10010
#define INF 0x3FFFFFFF
using namespace std;
typedef long long ll;
int n;
int dp[MAXN][MAXM]; 
int st[MAXN],ed[MAXN];
int pos[5],now;
void get_num(int x){
    now=x%10;
    pos[0]=x/10%10;
    pos[1]=x/100%10;
    pos[2]=x/1000;
}
int get_sum(){
    return pos[2]*1000+pos[1]*100+pos[0]*10+now;

}
int main(){
    SF("%d",&n);
    for(int i=1;i<=n;i++)
        SF("%d%d",&st[i],&ed[i]);
    memset(dp,0x3f3f3f3f,sizeof dp);
    dp[0][1]=0;
    for(int i=0;i<=n;i++)
        for(int j=9999;j>0;j--){
            if(dp[i][j]==0x3f3f3f3f)
                continue;
            get_num(j);
            int now1=now,p1;
            for(int k=0;k<3;k++)
                if(pos[k]){
                    now=pos[k];
                    p1=pos[k];
                    pos[k]=0;
                    int nxt=get_sum();
                    dp[i][nxt]=min(dp[i][nxt],dp[i][j]+abs(now1-p1)+1);
                    get_num(j);
                }
            if(i==n)
                continue;
            for(int k=0;k<3;k++){
                if(pos[k]){
                    now=pos[k];
                    p1=pos[k];
                    pos[k]=ed[i+1];
                    int nxt=get_sum();
                    dp[i+1][nxt]=min(dp[i+1][nxt],dp[i][j]+abs(now1-st[i+1])+1+abs(st[i+1]-now)+1);
                    get_num(j);
                }
                else{
                    now=st[i+1];
                    p1=pos[k];
                    pos[k]=ed[i+1];
                    int nxt=get_sum();
                    dp[i+1][nxt]=min(dp[i+1][nxt],dp[i][j]+abs(now1-now)+1);
                    get_num(j);
                }
            }
            now=ed[i+1];
            int nxt=get_sum();
            dp[i+1][nxt]=min(dp[i+1][nxt],dp[i][j]+abs(now1-st[i+1])+1+abs(st[i+1]-ed[i+1])+1);
        }
    int res=INF;
    for(int i=1;i<=9;i++)
        res=min(res,dp[n][i]);
    PF("%d",res);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值