用集团和限制建造最大的堆积塔

时间:2015-09-15 11:09:08

标签: c++ algorithm dynamic-programming

问题

问题在于建造由圆柱体组成的最高塔,遵守所有规则。

  • 将在桌子上安排一定数量的N个气瓶。
  • 每个圆柱都有一种颜色:红色,橙色,绿色或蓝色。
  • 每个圆柱体有一个高度h和一个半径为r的底座。
  • 要建造塔楼,应该将钢瓶堆叠起来 顶部圆柱体应该具有比底部小的底部 它下面的圆柱体。除了第一个圆柱体,它可以有底座 任何尺寸,因为它下面没有其他气缸。

对气缸的颜色也有一些非常有趣的限制。它们如下所述。

  • 红色圆柱体不能放在橙色圆柱体上
  • 橙色圆筒不能放在蓝色圆筒上
  • 蓝色圆柱体不能放在绿色圆柱体上
  • 绿色圆柱体不能放在红色圆柱体上

输入

  

输入包含几个测试用例。每个测试用例的第一行包含整数N(1 <= N <= 10 ^ 3),表示在N行之后排列在表上的柱面数,每行具有高度h(1 <=以厘米为单位的圆柱体的h <= 1000),圆柱体基部的半径r(1 <= r <= 1000)和表示圆柱体颜色的字p。这个词可以是:RED,ORANGE,GREEN或BLUE。输入结束表示为N = 0,不应处理。

输出

  

对于每个测试用例,您的程序应打印一行,其值为可构建的最大圆柱塔的高度,后跟单词&#34;厘米“。

示例输入

5   
5 3 RED    
4 2 ORANGE   
1 1 GREEN    
3 5 ORANGE    
2 4 BLUE    
3    
10 10 ORANGE    
5 10 GREEN    
6 5 RED    
0

示例输出

15 centimeter(s)    
11 centimeter(s)

我试图通过动态编程解决这个问题,但是需要超过8秒才能给出大输入的答案(在限制范围内);这个解决方案适合这个问题吗?还有其他算法吗?

#include <cstdio>
#include <unordered_map>
#include <string>
#include <algorithm>
#include <string.h>

#define MAX 1000

#define NON -1
#define RED 3
#define ORA 2
#define BLU 1
#define GRE 0

struct cylinder_t{
    int h,r,c;
    cylinder_t():h(0),r(0),c(0){}
    cylinder_t(int height, int radius, int color):h(height),r(radius),c(color){}
};

inline bool compare (const cylinder_t &i,const cylinder_t &j) {
    return i.r > j.r;
}

cylinder_t cylinder[MAX];
inline bool canPut(int i, int last_cylinder_onStack){

    if(last_cylinder_onStack == NON)
        return true;

    if (cylinder[i].r >= cylinder[last_cylinder_onStack].r)
        return false;

    if((cylinder[i].c - cylinder[last_cylinder_onStack].c + 4)%4 == 1)
        return false;

    return true;
}

int memo[MAX][MAX];
int dp(int tower_size, int size, int last_cylinder_onStack){
    if(tower_size == size)
        return 0;

    if(last_cylinder_onStack != NON && memo[tower_size][last_cylinder_onStack] != -1)
        return memo[tower_size][last_cylinder_onStack];

    int maxHeight = 0;
    for (int c = tower_size; c < size; ++c) {
        if(canPut(c, last_cylinder_onStack))
            maxHeight = std::max(maxHeight, cylinder[c].h + dp(tower_size + 1, size, c));
    }

    if(last_cylinder_onStack == NON)
        return maxHeight;
    return memo[tower_size][last_cylinder_onStack] = maxHeight;
}

int main(void){
    //clock_t t;
    //t = clock();

    std::unordered_map<std::string, int> map;
    map["RED"]    = RED;
    map["ORANGE"] = ORA;
    map["GREEN"]  = GRE;
    map["BLUE"]   = BLU;

    int n;
    while(scanf("%d",&n), n != 0){

        for (int i = 0; i < n; ++i) {
            int height,radius;
            char color[15];
            scanf("%d %d %s",&height,&radius,&color[0]);
            cylinder[i].h = height;
            cylinder[i].r = radius;
            cylinder[i].c = map[std::string(color)];
        }

        std::sort(cylinder, cylinder + n, compare);

        memset(memo, -1, sizeof(memo));
        printf("%d centimeter(s)\n",dp(0,n, NON));
    }

    //t = clock() - t;
    //printf("Took %lf seconds to execute \n",((double)t)/CLOCKS_PER_SEC);
}

我已经在JAVA中为这个问题制作了一个INPUT生成器:

import java.io.IOException;
import java.util.Random;


public class Main {

    public static void main(String[] args) throws IOException {
        Random r = new Random();
        String color[] = {"RED","ORANGE","GREEN","BLUE"};

        int t = 20;//number of test cases
        for (int i = 0; i < t; i++) {
            int n = r.nextInt(1000) + 1; //number of cylinders
            System.out.println(n);
            for (int j = 0; j < n; j++) {
                System.out.printf("%d %d %s\n",r.nextInt(1000) + 1,r.nextInt(1000) + 1,color[r.nextInt(4)]);
            }
        }

        System.out.println("0");
    }

}   

1 个答案:

答案 0 :(得分:3)

您的dp表同时包含tower_sizelast_cylinder_on_stack参数,这很奇怪。我认为dp应仅依赖于last_cylinder_on_stack。在递归函数中,你知道堆栈上的最后一个柱面,所以你显然应该只从last_cylinder_on_stack+1循环

所以我认为你应该摆脱last_cylinder_onStack参数并将主循环作为

for (int c = last_cylinder_onStack+1; c < size; ++c) {
    if(canPut(c, last_cylinder_onStack))
        maxHeight = std::max(maxHeight, cylinder[c].h + dp(size, c));
}