题意:
给你一个w*h的区域,给你n个不同的地毯,告诉你每个地毯的长宽,让你把区域铺满,地毯可以旋转,不能重叠,不能剪小。问你能不能铺满。其中1≤wi≤100;1≤hi≤100;1≤n≤7。
思路:
这属于小规模的平铺类搜索。
平铺:不允许重叠,将给出的一些方块(最容易处理的是长方形了)放置在一个目标区域内。
小规模:要放置的方块数量<10,放置的目标区域的边长<=100。
贪心策略是找到带有空闲单元格的最顶行,然后选择最左边的单元格。
然后搜一下就可以了。
我太菜了这种DFS不会写QAQ
然后学习了一下标程再写的QAQ
当然还有一种方法是全排列一下,根据顺序来放。
还是讲一下这深搜是怎么写的吧(每次写这种DFS就无从下手的感觉
先确定两个参数,x,y表示当前开始铺的位置。
枚举地毯,这里旋转用了swap,可以让代码简洁一点,如果这个地毯没有被用过,就验证一下能不能放(放了以后越界而且覆盖的地方之前都没有被铺过)。
如果可以放,就放进去,递归调用dfs(x+a,y),因为要尽量从最左上放,所以y不动,x+a,如果后面这样放是可以的就返回true,不行的话回溯,把标记还原。
还要注意dfs里边界条件,如果x为w的话就铺下一行,如果y为h就返回true,如果这个单元格被铺过了的话就铺左边一个。
写DFS的时候就心里觉得调起来肯定很麻烦就不敢写,这样不行,写之前细节都想想好,会好一点。
代码:
int w,h,c;
bool mp[110][110];
struct node
{
int a,b,cnt;
}carp[10];
bool dfs(int x,int y)
{
//printf("%d,%d\n",x,y);
if(x==w){/*printf("!\n");*/return dfs(0,y+1);}
if(y==h){/*printf("?\n");*/return true;}
if(mp[x][y]){/*printf(".\n");*/return dfs(x+1,y);}
for(int i=0;i<c;i++)
{
if(carp[i].cnt>0)
{
int cura=carp[i].a,curb=carp[i].b;
for(int j=0;j<2;j++)
{
swap(cura,curb);
if(x+cura>w)continue;
if(y+curb>h)continue;
int sign=0;
for(int k=0;k<cura&&sign==0;k++)
{
for(int l=0;l<curb&&sign==0;l++)
{
int curx=x+k,cury=y+l;
if(mp[curx][cury])sign++;
}
}
if(sign!=0)continue;
carp[i].cnt--;
for(int k=0;k<cura;k++)
for(int l=0;l<curb;l++)
{
int curx=x+k,cury=y+l;
mp[curx][cury]=true;
}
if(dfs(x+cura,y))return true;
carp[i].cnt++;
for(int k=0;k<cura;k++)
for(int l=0;l<curb;l++)
{
int curx=x+k,cury=y+l;
mp[curx][cury]=false;
}
if(cura==curb)break;
}
}
}
return false;
}
int main()
{
scanf("%d%d",&w,&h);
scanf("%d",&c);
memset(mp,0,sizeof(mp));
for(int i=0;i<c;i++)
scanf("%d%d%d",&carp[i].cnt,&carp[i].a,&carp[i].b);
if(dfs(0,0))printf("yes\n");
else printf("no\n");
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!