POJ1020 回溯算法和DFS的练习
POJ1020
题目大意 使用n个小正方形拼接为变长为m的大正方形,每个小正方形的大小为1-10, n的取值范围为1-16, 可以得知m的取值范围为1-40。
问, 现在给定 m 和n 已经n个小正方形的情况下,判断是否能够利用这个n个小正方形组成 这个变长为m的大正方形.
思路 : 1 刚开始在选择数据结构的表示时我用二维数组来表示这个原始的大的正方形,但发现回溯的时候,在还原正方形时显得比较复杂, 参考网上的做法应其实用1维的数组就可以表示这个大正方形的状态了。
2 同过读题后首先想到的就是通过暴力手段遍历各种组合试探,看是否能拼接成正方形, 如果为n个小正方形的话,最坏的情况应该是要试探n!个情况。
3 参照网上的思路 ,其实这是结合了回溯思想和DFS深度优先遍历的方法。
首先用一维的数组cols[41]的下标表示大数组的每一列,数组的元素值表示该列下已经用到第几行。
在每次放入一个变长为i的正方形之前,首先遍历原始的数组cols,找到已经被占用行数最小的那一行所在的列, 然后以该列和该行作为待放入的小正方形的左上角,(此时要判断是否可以放入该小正方形,即判断加入该小正方形后列和被占用的行的数是大于原始正方形的边长)
放入小正方形更新每一列所被占用的行, 递归调用下一行,当所有的小正方形都调用完时返回结果.
总结:
1 在选择数据结构存储待放入的小正方形,利用每块小正方形的边长不超过10 的特点,建立一个cake[11]的数组,数组的下标表示该小正方形的大小,数组的元素值表示该类边长的正方形的个数
2
二叉树的提出解决了 可以表示对象之间的层次关系, 而传统的数组和链表只能表示线性关系。
在搜索算法中最关键的不是匹配词语,而是要匹配词义。
基于二叉树的传统的搜索算法主要分为
BFS( Broad-first) 广度优先遍历 (主要用队列实现)
DFS() 深度优先遍历(主要用递归实现,其实也是利用栈的原理)
#include<iostream>
#include<stdio.h>
int cakeSize; //蛋糕的大小,即表示蛋糕的边长
int cake[11],cols[41]; //cake 表示每块蛋糕的大小 cols 表示每一行中被占用的列的数目
int number; //待切的蛋糕数
bool CutCake(int a)
{
int selectCol; //选择切蛋糕的行
int minRow; //选择的行中被占用的列
int i,j;
bool isok;
if(a==number)
{
return true;
}
minRow=41;
for(i=1;i<=cakeSize;i++) //确定从哪一行开始切蛋糕
{
if(cols[i]<minRow)
{
selectCol=i;
minRow=cols[selectCol];
}
}
//开始切蛋糕
for(i=10;i>0;i--)
{
//i=_Cake[i];
if(cake[i]>0&&(minRow+i-1)<=cakeSize&&(selectCol+i-1)<=cakeSize)
{
//现在开始切蛋糕
isok=true;
for(j=selectCol;j<selectCol+i;j++)
{
//if((cols[j]+i-1)>cakeSize)
if(cols[j]>minRow) //这里是判断的关键
{
isok=false;
break;
}
}
if(isok==true)
{
for(j=selectCol;j<selectCol+i;j++)
{
cols[j]+=i;
}
cake[i]--;
if(CutCake(a+1)==true) //开始递归切下一块蛋糕
{
return true;
}else
{
for(j=selectCol;j<selectCol+i;j++) //如果递归失败的话,还原数据
{
cols[j]=cols[j]-i;
}
cake[i]++;
}
}
}
}
return false;
}
int main(void)
{
int test_case=0;
int i,j,temp;
bool flag=false;
int sumArea;
//std::cin>>test_case;
scanf("%d",&test_case);
//std::cin>>cakeSize>>number;
while(test_case>0)
{
test_case--;
scanf("%d %d",&cakeSize,&number);
memset(cake,0,sizeof(cake));
sumArea=0;
for(i=0;i<number;i++) //确定待分切得蛋糕数
{
//std::cin>>temp;
scanf("%d",&temp);
cake[temp]++;
sumArea+=temp*temp;
}
flag=false;
if(sumArea!=cakeSize*cakeSize)
{
//待切蛋糕的总面积不等于原始蛋糕面积的话则作废
//std::cout<<"HUTUTU!"<<std::endl;
printf("HUTUTU!\n");
}else
{
for(i=1;i<=40;i++)
{
cols[i]=1;
}
flag=CutCake(0);
if(flag==true)
{
//std::cout<<"KHOOOOB!"<<std::endl;
printf("KHOOOOB!\n");
}else
{
//std::cout<<"HUTUTU!"<<std::endl;
printf("HUTUTU!\n");
}
}
}
return 0;
}