UVa 311 - Packets

題目:有1x1,2x2,3x3,4x4,5x5,6x6的方塊若干,問最少用幾個6x6的盒子可以放下。

分析:貪心。1x1的用來填充剩餘空間即可,任何空間都可以放下;

            首先,每個6x6,5x5,4x4都要單獨占一個盒子,因此把剩餘的空間填充2x2,1x1為最優;

            然後,剩下3x3,2x2,先按填滿的放置(4個3x3,9個2x2安組分配為最優);

            最後,剩下3x3少於4個,2x2少於9個,最多需要兩個盒子,1x1最後填充即可。

            (证明第二步、第三步为最优方式,一共36種組合,其中占2个盒子的为:

                <1,6>,<1,7>,<1,8>,<1,6>,

                <2,4>,<2,5>,<2,6>,<2,7>,<2,8>

                <3,2>,<3,3>,<3,4>,<3,5>,<3,6>,<3,7>,<3,8>

                對於每種情況分別加入<4,9>重新分配,,無法得到更小盒子數量,因此為最優分配)

說明:開始沒看出是貪心,利用dp求解3x3與2x2的分配方式╮(╯▽╰)╭。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

int block[7];
int maps[5][10] = {
	0,1,1,1,1,1,1,1,1,1,
	1,1,1,1,1,1,2,2,2,2,
	1,1,1,1,2,2,2,2,2,2,
	1,1,2,2,2,2,2,2,2,2,
	1,2,2,2,2,2,2,2,2,2};

int dp[505][505];

int main()
{
	while (~scanf("%d",&block[1])) {
		int sum = block[1];
		for (int i = 2; i <= 6; ++ i) {
			scanf("%d",&block[i]);
			sum += block[i];
		}
		if (!sum) break;
		
		//6x6
		int count = block[6];
		//5x5
		count += block[5];
		block[1] -= min(block[1], 11*block[5]);
		//4x4
		count += block[4];
		if (5*block[4] > block[2]) {
			block[1] -= min(block[1], 20*block[4]-4*block[2]);
			block[2] = 0;
		}else {
			block[2] -= 5*block[4];
		}
		/*
		//dp
		for (int i = 0; i <= block[3]; ++ i)
		for (int j = 0; j <= block[2]; ++ j)
			dp[i][j] = 100001;
		for (int i = 0; i <= 4; ++ i)
		for (int j = 0; j <= 9; ++ j)
			dp[i][j] = maps[i][j];
		for (int i = 0; i <= block[3]; ++ i)
		for (int j = 0; j <= block[2]; ++ j) {
			if (i >= 4 && j >= 0 && dp[i][j] > dp[i-4][j-0])
				dp[i][j] = dp[i-4][j-0]+1;
			if (i >= 3 && j >= 1 && dp[i][j] > dp[i-3][j-1])
				dp[i][j] = dp[i-3][j-1]+1;
			if (i >= 2 && j >= 3 && dp[i][j] > dp[i-2][j-3])
				dp[i][j] = dp[i-2][j-3]+1;
			if (i >= 1 && j >= 5 && dp[i][j] > dp[i-1][j-5])
				dp[i][j] = dp[i-1][j-5]+1;
			if (i >= 0 && j >= 9 && dp[i][j] > dp[i-0][j-9])
				dp[i][j] = dp[i-0][j-9]+1;
		}
		//dp 
		*/
		//贪心 
		//3x3
		count += block[3]/4;
		block[3] %= 4;
		//2x2
		count += block[2]/9;
		block[2] %= 9;
		//贪心 
		count += maps[block[3]][block[2]];
		count += (block[1]+9*block[3]+4*block[2]-36*maps[block[3]][block[2]]+35)/36;
		printf("%d\n",count);
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值