SRM538-div2-3-SkewedPerspectives


题目大意:
     有四种积木:1×1×1的红色、黄色、蓝色积木各一种,1×1×2的黑色积木一种。每一种积木的数量用int[] cube(3个元素,分别表示三种颜色的方块)和int B(黑色积木)来表示。
     用这些积木的一部分堆砌成若干个方柱(不超过w个),每个方柱都是1×1的截面(高度不一定相同),把这些方柱从左到右整齐排列好,然后整体向左侧投影,只有积木的左侧没有被其他积木挡住时才会有投影。把投影结果看作是一个个1×1分割的格子,从下到上,用一个字符串表示格子的颜色,'0','1','2'分别表示红黄蓝,‘b'表示黑色。
     给定一组积木和m,判断一系列投影结果string[] views中那些是可能的,哪些是不可能的。
     数据规模:w为[1,50], 各种颜色积木数均为[0,100], views包含[1,50]个字符串,每个字符串长度为[1,50] 
     
     

思路:
     这道题只需要模拟即可,部分地方需要使用贪心,关键是要抓好能断定投影失败的条件。
     堆砌过程如下:
     从下到上扫描投影并从左到右堆砌各个方柱。如果扫描到非黑色的积木,那么直接在当前方柱上加上该颜色积木。如果遇到的是黑色积木,那么:
  • 如果连续的黑色投影数为偶数,那么直接在当前方柱上加上该这些黑色积木。
  • 如果连续的黑色投影数为奇数,那么肯定无法在当前方柱搞定,需要往右移再堆砌一个方柱。最优的做法是直接让第一个黑色投影格子就是下一个方柱的对应黑色积木产生,并且该黑色积木的下一半被当前方柱挡住。假设当前方柱高度已经为h,那么该黑色积木应该从下一个方柱的h-1开始堆放。下面的h-1高度该如何堆砌先放着,用一个数组int[] need来保存,等最后再考虑。这个地方还需要注意一点,如果当前方柱的高度为0,那么是无法实现上面的做法的,所以还需要进一步判断:如果x为1,则该投影肯定是不可能的;如果x不等1,那么第一个方柱使用一个黑色积木,然后第二个方柱从高度1开始堆砌黑色积木。
     根据以上描述完成整个堆砌过程,记录所使用过的所有颜色积木的数量,所构建的方柱数量,以及need数组。各颜色积木的用量以及方柱数不得超过给定的条件。
     然后需要进一步判断剩下的积木是否可以满足need数组的需求。满足该条件只需要保证两点即可:1. need数组中,奇数元素的个数不超过剩余红黄蓝积木的总数。2. need数组的总和不超过所有剩余积木高度的总和(黑色积木高度为2)。  
     满足以上所有条件的投影便是可能的投影。由于判断逻辑比较繁琐,所以代码很容易写错,还好题目给的case比较强大,只要通过了case应该就可以通过system test。   

Java代码:
public class SkewedPerspectives
{
   
    private String solve(int[] cs, int B, int w, String v){
        int[] need = new int[w + 1];
        int b = B;
        int cw = 0;
        for(int h = 0; h < v.length() && cw < w; ++h){
            if(v.charAt(h) != 'b'){
                cs[v.charAt(h) - '0']--;
            }else{
                int cnt = 0;
                while(h + cnt < v.length() && v.charAt(h + cnt) == 'b') cnt++;
                if(cnt % 2 == 0){
                    b -= cnt / 2;
                }else{
                    if(h == 0){
                        if(cnt == 1){
                            return "invalid";
                        }else{
                            need[++cw] = 1;
                            b -= cnt / 2 + 1;
                        }
                    }else{
                        need[++cw] = h - 1;
                        b -= cnt / 2 + 1;
                    }
                }
                h += cnt - 1;
            }
        }
        if(cw >= w){
            return "invalid";
        }else{
            int num = 0;
            for(int i = 0; i < cs.length; ++i){
                if(cs[i] < 0){
                    return "invalid";
                }
                num += cs[i];
            }
            int sum = 0;
            for(int j = 0; j < w; ++j){
                num -= need[j] % 2;
                sum += ((need[j] >> 1) << 1);
            }
            if(b < 0 || num < 0){
                return "invalid";
            }
            if(2 * b + num >= sum){
                return "valid";
            }else{
                return "invalid";
            }
        }
    }
   
      public String[] areTheyPossible(int[] cubes, int B, int w, String[] views)
      {
            String[] res = new String[views.length];
            for(int i = 0; i < views.length; ++i){
                int[] cs = new int[cubes.length];
                for(int j = 0; j < cubes.length; ++j){
                  cs[j] = cubes[j];
              }
                if(B == 3 && i == views.length - 10){
                    int test = 0;
                }
                res[i] = solve(cs, B, w, views[i]);
            }
            return res;
      }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值