题解 | #种树#
种树
https://www.nowcoder.com/practice/52f25c8a8d414f8f8fe46d4e62ef732c
思路
由于同种类树不能相邻,因此我们若间隔种植同种树木,若能成功种植,其长度不会超过 。设第 种树木有 棵,根据 的奇偶性,我们可以考虑两种极端情况:
- 若 为奇数,则最多能种植的同种树木数量满足 ,如下图所示:
- 若 为偶数,则最多能种植的同种树木数量满足 ,如下图所示:
显然,若树木多于上述情况,则将不存在方案。故若 ,那么可以直接判断方案不存在。那么当对任意 ,时,一定存在不相邻种植的方案吗?
答案是一定的!我们可以尝试构造出这样的解:我们按树木编号顺序从头至尾间隔种植,到达尾部后重新从第二个槽位开始间隔种植。
下图我们依次按照蓝色、橙色、红色、黄色间隔种植,且 为偶数的情况。 如果此时存在相邻的同种树木,那么一定一棵来自于第一趟种植,一棵来自第二趟种植,如下图红色树木。 此时,红色树木数量为 ,而在 为偶数时,能种植的树木数量满足 ,因此这种情况只有两个同种树木相邻。此时我们变换策略,将所有红色树木种在偶数位或奇数位,那么其余位任意种植树木均满足条件。
当 为基数时,若发生相邻树木为同种的情况: 则必然有 ,此时所有红色树木应全部种植在奇数位,其他所有树木任意种植均满足条件。
综上所述,若所有树木均满足 ,则必然存在解。并且若存在 ,则第一个槽位只能种植该种树木,否则第一个槽位可以种植任意树木。
因此我们可以得到一个贪心方案:若有解,并且不存在 ,则我们置此槽位为序号最小的剩余树木,并在之后规模为 的数组寻找第一个槽位与该槽位不同的解;若存在 ,则直接置为 ,并在之后规模为 的数组寻找第一个槽位与该槽位不同的解。若无解,直接输出即可。
代码
#include <iostream>
using namespace std;
int N, M = 0;
int A[1001]{};
int res[2001]{};
int main() {
ios_base::sync_with_stdio(false);
cin>>N;
for(int i=1;i<=N;++i) { cin>>A[i]; M+=A[i]; }
for(int i=1;i<=N;++i) if((M+1)<2*A[i]) {
cout<<"-";
return 0;
}
for(int j=1;j<=M;++j){
int len = M+1-j;
int i=0;
if(len & 0x1) {
for(i=1;i<=N;++i) if(2*A[i]==len+1) {
res[j]=i;
--A[i];
break;
}
}
if(i==N+1 || !(len & 0x1)){
for(i=1;i<=N;++i) if(A[i]>0 && i!=res[j-1]) {
res[j]=i;
--A[i];
break;
}
}
}
for(int j=1;j<=M;++j) cout<<res[j]<<" ";
return 0;
}
- 时间复杂度:
- 空间复杂度: