题意:给定一个左视图,要求给定的方块数能否垒成这么一个视图。方块数不要求全部用完。垒数不能超过W。
解答:此题我们采用贪心解决。由于W有限,如果没有黑色的‘b’,我们是可以只用一垒就摆出给定的视图。贪最少的垒,只有到出现奇数个连续的‘b’时,这是我们要将2*1*1的black块挡住一半,使得左视图只看到一个‘b’,这时才要新摆放一个垒。
我们从后往前,从高往低摆放视图,至于需要用来作为垫高的底垫块放在最后考虑(用剩余的块来垫)。
从后往前考虑,0、1、2都可以直接放在一堆,不要另成一堆;只有当出现一个(奇数个)‘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