TOJ 3858 Home & GCPC 2015 D Carpets 小规模平铺类搜索
来源:互联网 发布:windows开始菜单在哪 编辑:程序博客网 时间:2024/05/29 10:59
这里讨论一下小规模平铺类搜索的一种写法。
说明一下讨论的范围:
- 平铺:不允许重叠,将给出的一些方块(最容易处理的是长方形了)放置在一个目标区域内
- 小规模:要放置的方块数量<10,放置的目标区域的边长<=100
OK,先TOJ 3858
3858 . Home
Time Limit: 1.0 Seconds Memory Limit: 65536K
Total Runs: 187 Accepted Runs: 60Poorman rents a new house in Beijing recently. He has some furnitures and wants to move them into his new house.
In order to make the problem more clearly, the new house is 10 × 10 square. Every furniture can be represented by a rectangle which is a × b ( a > 0 , b > 0 ). Now given you the information about the furnitures and tell us whether poorman can move all his furnitures into his new house.
Input
There are several test cases. For each test case, the first line contains a single integer n ( 0 < n < 10 ) which is the number of poorman’s furnitures. Then there will be n following lines. For each line, there are two integers a, b ( a > 0 , b > 0 ) which means the furniture’s size is a × b.
Output
For each test case, if poorman can move all his furnitures into his house successfully, print “Yes” in a line. Otherwise print “No”.
Sample Input
3
5 10
4 5
5 6Sample Output
Yes
Source: TJU 2012 Team Selection
凭直觉,很容易想到,规定好放置顺序和方向的情况下,尽量靠上能更多的节省空间。
那这样的话,如果我能规定顺序和旋转方向,枚举放在哪里合适的时候,直接越往上越好,或者说,在左上角(1,1),向下x增大,向右y增大的坐标系里,我只需要枚举所有可能的y,x利用这个贪心性质,直接尽量往上贴了。
那这样的话,在考虑一种约定的放置顺序和方向的时候,我们只要设置一个数组(下面的代码中的lowest),记录当前状态下,每一列最下面的x坐标是多少,放置的时候,考虑放置所影响的y的区间,并做相应修改即可。(记得备份当前状态,因为y还是要dfs枚举的)
有人要问了,贪心往上贴,留下一些空腔,其他小方块能放得下怎么办?
答案是,不要在意,我们要枚举这些方块的放置顺序和旋转方向,这样,一种顺序是长的方块先放,导致上面留下很大空间被浪费,没关系,等一下一定枚举得到小块先放上去再放大块的情况的。
在下面的代码实现中,用next_permutation()枚举放置顺序,dfs()里枚举放置方向和左上角的y的位置,dfs里记得要以复制数组的形式备份当前状态,回退的时候要还原(因为放置上去以后还原没法直接正确推测的,和下面的题不一样)。
时间复杂度:
参数带进去感觉,好大的复杂度啊,但是实际在TOJ上跑,0.00秒,无语。
其实时间常数上还是有一定优化空间的,下面再讨论。
#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>using namespace std;int n;int piece[10][2];int lowest[10];int baklowest[10][10];int perm[10];int lowestinRange(int st,int en){ int ans=0; for(int i=st;i<=en;i++)ans=max(ans,lowest[i]); return ans;}void backupLowest(int depth){ for(int i=0;i<10;i++)baklowest[depth][i]=lowest[i];}void restoreLowest(int depth){ for(int i=0;i<10;i++)lowest[i]=baklowest[depth][i];}bool found;void dfs(int depth){ if(depth==n){ found=true; return; } int id=perm[depth]; for(int i=0;i<=10-piece[id][0];i++){ int mark=lowestinRange(i,i+piece[id][0]-1); if(mark+piece[id][1]>10)continue; backupLowest(depth); for(int j=i;j<=i+piece[id][0]-1;j++) lowest[j]=mark+piece[id][1]; dfs(depth+1); if(found)return; restoreLowest(depth); } for(int i=0;i<=10-piece[id][1];i++){ int mark=lowestinRange(i,i+piece[id][1]-1); if(mark+piece[id][0]>10)continue; backupLowest(depth); for(int j=i;j<=i+piece[id][1]-1;j++) lowest[j]=mark+piece[id][0]; dfs(depth+1); if(found)return; restoreLowest(depth); }}int main(){ while(~scanf("%d",&n)){ for(int i=0;i<n;i++) scanf("%d%d",&piece[i][0],&piece[i][1]); for(int i=0;i<n;i++)perm[i]=i; found=false; do{ memset(lowest,0,sizeof(lowest)); dfs(0); }while(next_permutation(perm,perm+n)&&!found); puts(found?"Yes":"No"); } return 0;}
继续,GCPC 2015(2015 German Collegiate Programming Contest) 的D题
Problem D: Carpets
The computer science Professor Toving Liles loves the floor tiles in his office so much that he wants to protect them from damage by careless students. Therefore, he would like to buy cheap small rectangular carpets from the supermarket and cover the floor such that:
1. The entire floor is covered.
2. The carpets do not overlap.
3. The carpets are rotated arbitrarily.
4. No carpet is cut into pieces.
But when checking the supermarket’s stock he begins to wonder whether he can accomplish his plan at all. Can you help him?
Input
The first line contains two integers W and H describing the size of his room(1≤W,H≤100) .
The second line contains an integer c, denoting the number of different carpet colors the supermarket has in stock(1≤c≤7) .
Each of the following c lines consists of three integersai,wi , andhi , which means: thesupermarket’s stock containsai carpets of sizewi,hi and colori (1≤ai≤7;1≤wi≤100;1≤hi≤100) .
The supermarket has at most 7 carpets, i.e.∑iai≤7 .
Output
For the given room dimensions and the supermarket’s stock of carpets, print “yes” if it is possible to cover the room with carpets as specified above and “no” otherwise.Sample Input 1
2 4
2
3 1 3
2 2 1Sample Output 1
yesSample Input 2
100 100
3
4 42 42
1 100 16
1 32 42Sample Output 2
no
和上面的比较类似,但是有区别:这里的目标是,任选一部分,判断能否把整个区域平铺满。地毯数量减少了,区域增大了不少。
既然要考虑的是放满,同样可以选择,通过枚举来约定放置顺序和方向,在约定的基础上,枚举y,放置策略仍然是尽量往上放的贪心,不同的是,放置之前要考虑是否会产生一个空腔,如果会产生,那就不应该放上去。
看上去很不错,可是交上去就TLE了。
有一个贪心的性质是这题新增且需要利用的:你一定要把最上面有缺的那一行用方块填满,如果手上剩下的方块不能填满,那前面的放置方法就不正确。而且,如果最高的有空缺的那一行,有空缺的y有多个,你肯定要把最左的y能找个方块恰当的放上去,不然那个空没办法填满,铺满也就无从谈起。
所以这里在写的时候,对当前要继续考虑的状态,先找到放置方块总高度最小且最左的y,然后,只用对着那个y,把那个y当做必须要放好的左上角位置,枚举剩下的方块放上去,直到铺满,或者试完以后还是没法铺满为止。
时间复杂度:
其中
而且,
#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <limits.h>#include <math.h>#include <algorithm>using namespace std;typedef long long ll;int piece[15][2];bool taken[15];int height[105];int pcnt=0;int totw,toth;bool placeAble(int stw,int len,int h){ if(height[stw]+h>toth)return false; if(stw+len>totw)return false; for(int i=stw;i<stw+len-1;i++){ if(height[i]!=height[i+1]){ return false; } } return true;}bool fullfill(){ for(int i=0;i<totw;i++){ if(height[i]!=toth)return false; } return true;}void place(int stw,int len,int h){ for(int i=stw;i<stw+len;i++){ height[i]+=h; }}bool dfs(int depth){ if(fullfill())return true; if(depth>=pcnt)return false; int minh=205; for(int j=0;j<totw;j++)minh=min(minh,height[j]); for(int j=0;j<totw;j++){ if(minh==height[j]){ for(int i=0;i<pcnt;i++){ if(!taken[i]){ if(placeAble(j,piece[i][0],piece[i][1])){ place(j,piece[i][0],piece[i][1]); taken[i]=true; if(dfs(depth+1))return true; taken[i]=false; place(j,piece[i][0],-piece[i][1]); } if(placeAble(j,piece[i][1],piece[i][0])){ place(j,piece[i][1],piece[i][0]); taken[i]=true; if(dfs(depth+1))return true; taken[i]=false; place(j,piece[i][1],-piece[i][0]); } } } break; } } return false;}int main(){ int c; scanf("%d%d%d",&totw,&toth,&c); for(;c--;){ int a,wi,hi; scanf("%d%d%d",&a,&wi,&hi); for(;a--;){ piece[pcnt][0]=wi; piece[pcnt++][1]=hi; } } puts(dfs(0)?"yes":"no"); return 0;}
- TOJ 3858 Home & GCPC 2015 D Carpets 小规模平铺类搜索
- TOJ 3858 Home 搜索
- [TOJ 1636] Going Home
- 关于小规模垂直搜索的想法
- Direct 2D 平铺位图.
- TOJ 1009. Sticks 【搜索+剪枝】
- 搜索——TOJ 4165
- POJ 2032 Square Carpets
- toj 1056 Labyrinth 搜索,树的直径
- TOJ 1551 Power Hungry Cows -- 搜索
- 【TOJ 3403】Treasure Division 【双向搜索】
- 搜索 D
- 搜索--D
- 搜索 D
- 搜索-D
- 搜索-D
- 搜索 D
- 搜索-D
- LogUtils的介绍
- DBWn 进程和 DB_WRITER_PROCESSES/DBWR_IO_SLAVES 参数
- RJ45接口定义---dog0138
- java的system.arraycopy()方法
- log4cplus 使用方法 配置
- TOJ 3858 Home & GCPC 2015 D Carpets 小规模平铺类搜索
- binbinyang---eclipse中show whitespace characters按钮编辑器中显示导致恶心的乱码
- powerbuilder连接二个数据库时更新组件时出现问题
- iOS Xcode快速打开应用的Sandbox
- NOIP 2005 篝火晚会 COGS 112(只是用到置换的一个小概念而已)
- 黑马程序员——基础知识——语句结构
- Android引用Library的若干问题(全都是坑啊,一定要注意了)
- ios开发之 获取APP版本号/跳转APPStore(下载页/评论页)
- lintcode-区间求和I-206