POJ 1020 Anniversary Cake 回溯DFS

题意:给你一个大的正方形,和一些小的正放形,问你,这些小的正方形能不能填满整个大的正方形,不能有重合。

思路:首先以先选择大的正方形为优,留下的小的正方形的灵活性高,填放正方形的方法是,最作最上开始,先向num[a](每a行已经被用过的1*1的正方形数量)最小的行开始填写,如果连续的num[i]=num[a],那么就可以往上填写边长<=|a-i|+1的小正方形了。就当前来说,对于可以放入的小正方形,我们先把它放在这里,dfs继续,如果成功表示这里的放这个正方形是正确的,如果不可以,那么这个位置就要改变为其它的边长更小的小正方形了。

我看题解看了一上午…………

//属于尝试位置的问题 ,如果这里放了这个,那么它是否可以得到正确的答案 
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x7fffffff
using namespace std;
int Z,n;
int sidenum[20],sum,bignum;
void Input()
{
	sum=0;bignum=0;
	scanf("%d %d",&Z,&n);
	memset(sidenum,0,sizeof(sidenum)); 
	for(int i=1;i<=n;i++)
	{
		int a;
		scanf("%d",&a);
		sidenum[a]++;
		sum+=a*a;
		if(a>Z/2) bignum++; 
	}
}
int hang[50];
int getmin()
{
	int mmin=inf,mark;
	for(int i=1;i<=Z;i++)
	{
		if(mmin>hang[i])
		{
			mmin=hang[i];
			mark=i;
		}
	}
	return mark;
}
int dfs(int used)
{
	int falg=0;
	if(used==n) return 1;
	int row=getmin();
	for(int i=10;i>=1;i--)
	{
		falg=0;
		if(sidenum[i]&&row+i-1<=Z&&hang[row]+i<=Z)
		{
			int mark=1;
			for(int j=row;j<=row+i-1;j++)
			{
				if(hang[j]>hang[row])
				{
					mark=0;
					break;
				}
			}
			if(mark) falg=1;
		}
		if(falg)
		{
			sidenum[i]--;
			for(int j=row;j<=row+i-1;j++)
			{
				hang[j]+=i;
			}
			if(dfs(used+1)) return 1;
			for(int j=row;j<=row+i-1;j++)
			{
				hang[j]-=i;
			}
			sidenum[i]++;
		}
	}
	return 0;
}
void treatment()
{
	memset(hang,0,sizeof(hang));
	if(sum==Z*Z&&bignum<=1) 
	{
		if(dfs(0)) printf("KHOOOOB!\n");
		else printf("HUTUTU!\n");
	}
	else printf("HUTUTU!\n");
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		Input();
		treatment();
	}
	return 0;
} 

你可能感兴趣的:(poj,DFS)