poj 1020

大致题意也就是给出大正方形和多个小正方形的边长,用多个小正方形能否拼成一个大正方形。

这是一道搜索的题目,如果暴搜的话,边长为23左右就出不来结果过了。看了大牛的思想有很多方法可以剪枝的。

1、  小蛋糕用一个cake[11]的数组来存,cake[i]表示边长为i的蛋糕有cake[i]个,这样可以避免相同的蛋糕多次判断;

2、  用一维的col[41]来代替二维数组,col[i]表示第i行已经用了前col[i]列;

3、  遇到合适情况直接返回,不必要再往下搜索了;

4、  所有的小蛋糕面积和等于大蛋糕面积;

接下来说怎么搜索吧;

1、在col[]数组中找出使用的最小的行minRow,同时也就找出了下一次方小蛋糕的左上顶点;

2、然后在cake[]数组中找可以放置的蛋糕,“可以放置”是一个重要的条件判断;

   (1)minRow+i-1<=size(i表示边长为i的蛋糕,size表示大蛋糕的边长)

   (2)col[minRow]+i<=size

   (3)col[j]+i<=size  (minRow<=j<minRow+i-1)

   找不到可以放置的直接返回false;

3、放置成功后,重复1,直到放置完毕。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int col[41],cake[11],size,number;
int GetMinRow()
{
	int i,minRow,min=41;
	for(i=1;i<=size;i++)
		if(col[i]<min)
		{
			min=col[i];
			minRow=i;
		}
	return minRow;
}
int dfs(int curNum)
{
	int j,i,minRow;
	bool ok=false;
	if(curNum==number) 	return 1;

	minRow=GetMinRow();

	for(j=10;j>0;j--)
	{
		ok=false;
		if(cake[j] && minRow+j-1<=size && col[minRow]+j<=size)
		{
			for(i=minRow;i<minRow+j;i++)
			{
				if(col[i]>col[minRow]) break;
			}
                            if(i==minRow+j) ok=true;
		}
		if(ok)
		{
			cake[j]--;
			for(i=minRow;i<minRow+j;i++)
			{
				col[i]+=j;
			}

			if(dfs(curNum+1)) return 1;

			for(i=minRow;i<minRow+j;i++)
			{
				col[i]-=j;
			}
			cake[j]++;
		}
	}
	return 0;
}
int main()
{
	int i,n,sum,c;
	scanf("%d",&n);
	while(n--)
	{
		memset(cake,0,sizeof(cake));
		scanf("%d%d",&size,&number);
		for(sum=0,i=0;i<number;i++)
		{
			scanf("%d",&c);
			cake[c]++;
			sum+=c*c;
		}
		if(sum!=size*size) 
		{
			printf("HUTUTU!\n");
			continue;
		}
		memset(col,0,sizeof(col));
		if(dfs(0)==0)
			printf("HUTUTU!\n");
        else
			printf("KHOOOOB!\n");
	}
	return 0;
}

 

posted @ 2011-10-31 11:37  书山有路,学海无涯  阅读(1467)  评论(1编辑  收藏  举报