(2022牛客多校四)H-Wall Builder II(思维)

该博客介绍了如何解决一个计算机科学竞赛题目,涉及将不同大小的矩形拼接成一个大矩形以使周长最小。作者通过分析数据范围和利用数学原理,提出从面积的平方根开始枚举长和宽,并采用贪心策略来填充矩形。文章提供了详细的算法思路和C++代码实现,展示了如何判断能否用给定的小矩形拼接,并输出最小周长的结果。
摘要由CSDN通过智能技术生成

题目:

样例输入:

4
1
2
3
4

样例输出:

4
0 0 1 1
8
0 1 1 2
1 1 2 2
0 0 2 1
14
2 1 3 2
3 1 4 2
4 1 5 2
3 0 5 1
0 1 2 2
0 0 3 1
18
4 0 5 1
2 3 3 4
3 3 4 4
4 3 5 4
3 1 5 2
3 2 5 3
0 3 2 4
0 1 3 2
0 2 3 3
0 0 4 1

题意:给n个1*1的矩形,n-1个1*2的矩形,n-2个1*3的矩形,1个1*n的矩形,把这些矩形拼接成一个大矩形,求大矩形的最小周长。

分析:看了下数据范围,发现n是小于200的。由于我们怎么拼接,最后形成的矩形面积一定是固定的,有个显然的道理就是面积一定的情况下长和宽差越小周长就越小,因为由均值不等式可得ab<=((a+b)/2)^2,等号在a=b时取得,所以我们肯定是从面积的平方根开始枚举长和宽,然后逐一判断用给定的多个小矩形能否拼接成w*h的矩形,单独写一个函数判断即可,比如我们枚举宽,那么能够组成一个矩形的第一个条件就是S%w*w==S,其次才是看能否用小矩形拼接得到。那么我们怎么判断能否用小矩形拼接得到呢?有一个贪心的策略就是说每次填充我们都尽量选择大的矩形,为什么这样一定是最优的呢?其实假如我们现在需要一个1*x的矩形,我们可以由一个1*x的矩形充当,也可以由多个更小的矩形充当,当我们需要一个更小的矩形时,1*x的矩形却没办法分开,但是我们可以用小矩形去填充,而且任何时候小矩形都可以代替大矩形,所以这样贪心一定是正确的。

最后我们用一个vector p[i]记录第i行填的小矩形的宽即可

下面是代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
int n;
int cnt[N];
vector<int>p[N];//p[i]存第i行组成的矩形宽度 
bool check(int w,int h)
{
	for(int i=1;i<=h;i++) p[i].clear();
	for(int i=1;i<=n;i++) cnt[i]=0;
	for(int i=1;i<=h;i++)
	{
		int t=w;
		for(int j=n;j>=1;j--)
		{
			while(cnt[j]<n+1-j&&t>=j)
			{
				p[i].push_back(j);
				cnt[j]++;
				t-=j;
			}
			if(!t) break;
		}
		if(t) return false;
	}
	return true;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		long long ans=0;
		for(int i=1;i<=n;i++)
			ans+=i*(n+1-i);
		for(int i=(int)sqrt(ans);i<=ans;i++)
		{
			if(ans/i*i!=ans) continue;
			if(check(i,ans/i))
			{
				printf("%d\n",(i+ans/i)*2);
				for(int j=ans/i;j>=1;j--)
				{
					int t=0;
					for(int k=0;k<p[j].size();k++)
					{
						printf("%d %d %d %d\n",t,j-1,t+p[j][k],j);
						t+=p[j][k];
					}
				}
				break;
			}
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值