编程之美:小飞的电梯调度(k次停留)

问题.有一栋楼,一共有N层,要去每一层的人分别是A[1],A[2]....A[N],如果电梯可以停K次,问停在哪K层让所有人走的矩离最短?


解题思路参考:http://blog.163.com/guixl_001/blog/static/41764104201082062317857/

这里通过动态规划来求解,其中map[i][j]记录了考虑在1层到j层停留i次时的最优结果,minFloors[i][j]记录了i层到j层间只停留一次时的最优结果。当i = 1时,map[1][j]的值即为minFloors[1][j]的值,当i > 1时,其转移方程为map[i][j] = max{map[i - 1][k] + minFloors[k][j]},其中1 <= k <= j。以下是具体代码:

int func1(int *list, int startFloor, int endFloor) {

if(startFloor == endFloor) {
return 0;
}
int ret = 0;
int n1 = 0, n2 = list[startFloor], n3 = 0;
for(int i = startFloor + 1; i <= endFloor; i ++) {
n3 += list[i];
ret += list[i] * (i - startFloor);
}
for(int i = startFloor + 1; i <= endFloor; i ++) {
if(n3 > n1 + n2) {
ret -= n3 - n1 - n2;
n1 += n2;
n2 = list[i];
n3 -= n2;
} else {
break;
}
}
return ret;
}


void func2(int *list, int floor, int times, int &minFloor) {
int cnt = 0;
for(int i = 1; i <= floor; i ++) {
if(list[i] > 0) {
cnt ++;
}
}
if(cnt <= times) {         //当电梯需要停下的次数小于可以停下的次数时,最优情况为0
minFloor = 0;
return;
}
int map[LEN][LEN];             //map[i][j] 表示对于需要在1-j层下的乘客在停i次的情况下的最优值;
int minFloors[LEN][LEN];           //minFloor[i][j]表示在i层到j层下的乘客在停1次的情况下的最优值。
for(int i = 1; i <= floor; i ++) {
for(int j = i; j <= floor; j ++) {
minFloors[i][j] = func1(list, i, j);
}
}
for(int i = 1; i <= floor; i ++) {
map[1][i] = minFloors[1][i];
}
int temp = INF;
for(int i = 2; i <= times; i ++) {
for(int j = 1; j <= floor; j ++) {
temp = INF;
for(int k = 1; k <= j; k ++) {
if(map[i - 1][k] + minFloors[k][j] < temp) {
temp = map[i - 1][k] + minFloors[k][j];
}
}
map[i][j] = temp;
}
}
minFloor = map[times][floor];
}


int main(void) {
int list[LEN];
for(int i = 0; i < LEN; i ++) {
list[i] = 0;
}
int n;
cin >> n;
int floor, times;
cin >> floor >> times;
int stopFloor, peopleNum;
for(int i = 0; i < n; i++) {
cin >> stopFloor >> peopleNum;
list[stopFloor] = peopleNum;
}
int minFloor;
func2(list, floor, times, minFloor);
cout << minFloor << endl;
return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值