coj 1509 Build the given towers

题意:给定一个左视图,要求给定的方块数能否垒成这么一个视图。方块数不要求全部用完。垒数不能超过W

 

解答:此题我们采用贪心解决。由于W有限,如果没有黑色的‘b’,我们是可以只用一垒就摆出给定的视图。贪最少的垒,只有到出现奇数个连续的‘b’时,这是我们要将2*1*1black块挡住一半,使得左视图只看到一个‘b’,这时才要新摆放一个垒。

我们从后往前,从高往低摆放视图,至于需要用来作为垫高的底垫块放在最后考虑(用剩余的块来垫)。

从后往前考虑,012都可以直接放在一堆,不要另成一堆;只有当出现一个(奇数个)‘b

时,才要另成一堆,连续的多个‘b’可以两两算作一块,且放在同一堆中,当最后存在一个‘b

时,我们需要另成一堆,挡住后面的black块的一个‘b’部分。W--

 

W<0或方块数不够时,不能摆出。

被挡住的底部,需要额外的块垫在下面,black块(1*1*2)优先作垫子,因为单块(1*1*1)可以

放在任何位置(即可以代替black块,而black块不能代替单块,所以能先用black块的尽量先用black块)

 

 

考虑‘#bbb(奇数个连续的b)的情况,#不能是‘b,可以为空或0,1,2。视线从左往右。

#为空时,即'bbb',只能是(1)的情况。'?'{0,1,2}

#非空时,采用(2),会使得需要的垫子最少。(显然(1)中有重叠的部分b,比(2)要多花费2个垫子)


代码:

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    int a,b,c,d,t;
    int a1,b1,c1,d1,w1;
    char str[110];
    int no[110];
    int sum, h , len , flag ;
    while(scanf("%d%d%d",&a1,&b1,&c1)!=EOF)
    {
        scanf("%d",&d1);
        scanf("%d",&w1);
        scanf("%d",&t);
        while(t--)
        {
            flag=1;
            scanf("%s",str);
            memset(no,0,sizeof(no));
            a=a1; b=b1; c=c1; d=d1; 
            len=strlen(str);
            int k=1; 
            for(int i=len-1; i>=0; i--)
            { 
                if(str[i]=='0') a--;
                else if(str[i]=='1')   b--;  
                else if(str[i]=='2')   c--;  
                else 
                {
                    if(i==0) {flag=0; } 
                    h=0;
                    while(str[i]=='b' && i>=0) { h++; i--;} 
                    i++;
                    d-=(h+1)/2;    
                    if(h%2==1)
                    {
                        if(i>0) 
                        {
                            no[k]=(i-1);  k++;
                        }
                        else 
                        {
                            no[k]=1;  k++;
                        }
                    }
                } 
                if(a<0||b<0||c<0||d<0)   { flag=0;}
                if(flag==0) break;
            }  
            if(k>w1)  {flag=0;} 
            sum=0;  int num=0;
            for(int i=1;i<=k;i++)  { num+=no[i]/2;  sum+=no[i]%2;}
            num-=d;  if(num<0) num=0;    //之前这里num-=d*2  错了 
            if(sum+num*2>a+b+c)  flag=0;  
            if(flag) printf("valid\n");
            else printf("invalid\n");
        }
    }
    return 0;
}

测试数据:

0 0 0 3
2
1
bbb

1 1 0 3
2
1
10bbb

1 1 1 2
2
1
b1b

0 0 0 2
2
1
bbbb

1 0 0 10
10 
1
0b

1 0 0 10
2
1
bb0b


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值