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;

}

 

你可能感兴趣的:(poj)