搜索 【uva1602】Lattice Animals (练习题7-14 网格动物)
2017-01-05 21:41
519 查看
7-14 网格动物(Lattice Animals uva 1602)
(animals.cpp,Time limit: 3.000 seconds)
题目描述:
给你一个w*h的网格,你可以用含有n个方块块去填充它,要求这n个方块连同,想知道一共有多少中填充方法(连通就不用解释了……吧)。
注:如果一个图形能通过另一个图形平移或者旋转得到,那么认为这两个图形是相同的。
(以上是我自己理解的,如果有不清晰的地方……可以看英文原版)
举例子:
第一行:用5个方块的连通块填充2*4的方格,有5种填法。
第二行:用8个方块的连通块填充3*3的方格,有3种填法。
输入格式:
多组数据。
每行3个正整数n,w,h(1<=n<=10,1<=w,h<=n)
输出格式:
对于每组数据输出一行一个整数,代表有多少种填充方式。
样例输入:
5 1 4
5 2 4
5 3 4
5 5 5
8 3 3
样例输出:
0
5
11
12
3
题目分析:(搜索+set判重)
这种构造图形的题只能搜索了,重点是怎么搜,搜的时候要注意什么。
比较容易想到分层搜索,按照方块的数量来分层。
如果要是bfs搜到第10层就不要扩展新的状态。
如果dfs就迭代加深,搜到10层就回溯,我用的是深搜。
这道题其实没有什么技巧可言,在第一层的时候只有一种情况,就是一个方块,我们把这个图形储存下来,用它来扩展下一层的图形。
然后再用第二层得到的新图形来扩展第三层的图形,以此类推。
由于旋转平移和翻转之后如果图形相同答案不重复计算,所以需要判重,本来是想用hash的,但是本蒟蒻想不到一个把图形转成数字的好方法,所以就用set暴力判重了。
一个图形通过旋转和翻转会得到8种图案,我们可以用坐标的形式存储这个图形,并通过四次旋转90度,并且每次旋转之后翻转的方式得到8种图案。
因为平移也会影响坐标,所以我们统一把图案移动到第一象限,且使这个图案离坐标轴尽可能近,这样每种图案就只有八种表示方式。我们只把其中一个扔到set里,然后每次得到一个新的图案时,就用它的八种形式在set中跑一边判重,只要有一个在set出现过就可以减掉了。
这样我们保证所有的有用的图形都会扩展其它图形一次,而其实图形的总数只有6473,一个图形最多扩展出其它的图形也只有十几个,那么时间复杂度的级别在1e6左右,即使时限是1秒也跑出来了,都不用剪枝(也没有什么可以减的了)。
但是这道题是多组数据,如果你每次都搜一遍,把时间复杂度乘以300,那就很玄学了,所以你可以先把所有的数据都跑出来,存到一个数组里,最后一起输出结果。
代码如下(代码解释在代码后):
代码解释:
此下文段送给我的学弟学妹们(自认为代码可读性还可以,但是还是想写一写)。
结构体point代表点,x,y代表横纵坐标。
结构体graph代表图案,里面存储10个点代表具体的图案,sz代表这个图案的大小(即该图案由多少个方块构成)
因为graph要判重,所以要重定义 < 运算符。
translation是把所有的点排序并把整个图形平移到第一象限处。
turn是把这个图形逆时针旋转90度。
flip是把该图案翻转并返回当前图案。
calculate是计算当前图案的宽和高。
dfs:
枚举当前图案的每一个点并且枚举向哪个方向扩展。
第一次要判断是否这个点已经在这个图形中出现过,
第二次要判断增加这个点之后的图形是否已经出现过。
如果是可行解,就统计答案,并搜索下一层。
dfs之后的ans[i][j][k]表示表示用i个方块恰好填充j*k的网格的方案数。
我们需要把答案统计起来。
之后的for循环就是做这个用的(具体原理就不细说了,如果不明白的话再开一个数组暴力统计也可以,毕竟n<=10,n^5都能过)。
(animals.cpp,Time limit: 3.000 seconds)
题目描述:
给你一个w*h的网格,你可以用含有n个方块块去填充它,要求这n个方块连同,想知道一共有多少中填充方法(连通就不用解释了……吧)。
注:如果一个图形能通过另一个图形平移或者旋转得到,那么认为这两个图形是相同的。
(以上是我自己理解的,如果有不清晰的地方……可以看英文原版)
举例子:
第一行:用5个方块的连通块填充2*4的方格,有5种填法。
第二行:用8个方块的连通块填充3*3的方格,有3种填法。
输入格式:
多组数据。
每行3个正整数n,w,h(1<=n<=10,1<=w,h<=n)
输出格式:
对于每组数据输出一行一个整数,代表有多少种填充方式。
样例输入:
5 1 4
5 2 4
5 3 4
5 5 5
8 3 3
样例输出:
0
5
11
12
3
题目分析:(搜索+set判重)
这种构造图形的题只能搜索了,重点是怎么搜,搜的时候要注意什么。
比较容易想到分层搜索,按照方块的数量来分层。
如果要是bfs搜到第10层就不要扩展新的状态。
如果dfs就迭代加深,搜到10层就回溯,我用的是深搜。
这道题其实没有什么技巧可言,在第一层的时候只有一种情况,就是一个方块,我们把这个图形储存下来,用它来扩展下一层的图形。
然后再用第二层得到的新图形来扩展第三层的图形,以此类推。
由于旋转平移和翻转之后如果图形相同答案不重复计算,所以需要判重,本来是想用hash的,但是本蒟蒻想不到一个把图形转成数字的好方法,所以就用set暴力判重了。
一个图形通过旋转和翻转会得到8种图案,我们可以用坐标的形式存储这个图形,并通过四次旋转90度,并且每次旋转之后翻转的方式得到8种图案。
因为平移也会影响坐标,所以我们统一把图案移动到第一象限,且使这个图案离坐标轴尽可能近,这样每种图案就只有八种表示方式。我们只把其中一个扔到set里,然后每次得到一个新的图案时,就用它的八种形式在set中跑一边判重,只要有一个在set出现过就可以减掉了。
这样我们保证所有的有用的图形都会扩展其它图形一次,而其实图形的总数只有6473,一个图形最多扩展出其它的图形也只有十几个,那么时间复杂度的级别在1e6左右,即使时限是1秒也跑出来了,都不用剪枝(也没有什么可以减的了)。
但是这道题是多组数据,如果你每次都搜一遍,把时间复杂度乘以300,那就很玄学了,所以你可以先把所有的数据都跑出来,存到一个数组里,最后一起输出结果。
代码如下(代码解释在代码后):
#include<cstdio> #include<algorithm> #include<set> #include<iostream> using namespace std; const int INF=1000; inline int Min(int x,int y) {return x<y?x:y;} inline int Max(int x,int y) {return x>y?x:y;} struct point{ int x,y; bool operator == (const point c) const {return x==c.x && y==c.y;} bool operator < (const point c) const {return x<c.x || (x==c.x && y<c.y);} point operator + (const point c) { static point ans; ans.x=x+c.x; ans.y=y+c.y; return ans; } }; const point trans[4]={{0,1},{0,-1},{1,0},{-1,0}}; struct graph{ point spot[11]; int sz; bool operator < (const graph c) const { if(sz!=c.sz) return true; for(int i=0;i<sz;i++) { if(spot[i]<c.spot[i]) return true; if(c.spot[i]<spot[i]) return false; } return false; } void translation() { sort(spot,spot+sz); int xmin=INF,ymin=INF; for(int i=0;i<sz;i++) { xmin=Min(xmin,spot[i].x); ymin=Min(ymin,spot[i].y); } xmin=1-xmin,ymin=1-ymin; for(int i=0;i<sz;i++) { spot[i].x+=xmin; spot[i].y+=ymin; } return; } void turn() { for(int i=0;i<sz;i++) { swap(spot[i].x,spot[i].y); spot[i].x=-spot[i].x; } translation(); return; } friend graph flip(graph c) { for(int i=0;i<c.sz;i++) c.spot[i].x=-c.spot[i].x; c.translation(); return c; } void calculate(int &wide,int &height) { int minx=INF,maxx=-INF,miny=INF,maxy=-INF; for(int i=0;i<sz;i++) { minx=Min(minx,spot[i].x); maxx=Max(maxx,spot[i].x); miny=Min(miny,spot[i].y); maxy=Max(maxy,spot[i].y); } wide=maxx-minx+1; height=maxy-miny+1; } }variable; set<graph> V[11]; int ans[11][11][11]; int n,w,h; void dfs(int c) { const graph cur=variable; for(int i=0;i<c;i++) for(int j=0;j<4;j++) { variable=cur; point temp=variable.spot[i]+trans[j]; bool judge=true; for(int k=0;k<variable.sz;k++) if(temp==variable.spot[k]) { judge=false; break; } if(!judge) continue; variable.spot[variable.sz++]=temp; for(int k=1;k<=4;k++) { variable.turn(); if(V[c+1].find(variable)!=V[c+1].end()) { judge=false;break;} graph flipping = flip(variable); if(V[c+1].find(flipping)!=V[c+1].end()) { judge=false;break;} } if(!judge) continue; int wide,height; variable.calculate(wide,height); if(wide<height) swap(wide,height); ans[c+1][wide][height]++; V[c+1].insert(variable); if(c==9) continue; dfs(c+1); } return; } void get_ans() { variable.sz=1; variable.spot[0].x=1; variable.spot[0].y=1; ans[1][1][1]++; V[1].insert(variable); dfs(1); for(int i=1;i<=10;i++) for(int j=1;j<=10;j++) for(int k=1;k<=10;k++) ans[i][j][k]+=ans[i][j-1][k]+ans[i][j][k-1]-ans[i][j-1][k-1]; for(int i=1;i<=10;i++) for(int j=1;j<=10;j++) for(int k=1;k<j;k++) ans[i][k][j]=ans[i][j][k]; } int main() { get_ans(); while(scanf("%d%d%d",&n,&w,&h)!=EOF) printf("%d\n",ans [w][h]); return 0; }
代码解释:
此下文段送给我的学弟学妹们(自认为代码可读性还可以,但是还是想写一写)。
结构体point代表点,x,y代表横纵坐标。
结构体graph代表图案,里面存储10个点代表具体的图案,sz代表这个图案的大小(即该图案由多少个方块构成)
因为graph要判重,所以要重定义 < 运算符。
translation是把所有的点排序并把整个图形平移到第一象限处。
turn是把这个图形逆时针旋转90度。
flip是把该图案翻转并返回当前图案。
calculate是计算当前图案的宽和高。
dfs:
枚举当前图案的每一个点并且枚举向哪个方向扩展。
第一次要判断是否这个点已经在这个图形中出现过,
第二次要判断增加这个点之后的图形是否已经出现过。
如果是可行解,就统计答案,并搜索下一层。
dfs之后的ans[i][j][k]表示表示用i个方块恰好填充j*k的网格的方案数。
我们需要把答案统计起来。
之后的for循环就是做这个用的(具体原理就不细说了,如果不明白的话再开一个数组暴力统计也可以,毕竟n<=10,n^5都能过)。
相关文章推荐
- 例题7-14 网格动物 UVa1602
- Uva 1602 Lattice Animals (网格动物)
- UVa 1602 Lattice Animals 网格动物
- 例题7-14 网格动物(Lattice Animals, ACM/ICPC NEERC 2004, UVa1602)
- UVA1602 Lattice Animals 网格动物 (暴力,STL)
- UVA-1602 Lattice Animals 搜索问题(打表+set)
- Uva1602 Lattice Animals 【枚举打表+形状判重】【例题7-14】
- 【例题 7-14 UVA-1602】Lattice Animals
- [Uva1602][Poj2170][Zoj2669][Northeastern Europe 2004] Lattice Animals 【set+傻瓜搜索】
- UVa 1602 网格动物(回溯)
- Lattice Animals UVA - 1602
- UVa1602 - Lattice Animals
- 搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)
- UVA - 1602 Lattice Animals : 完备信息 set
- UVA 1602 Lattice Animals
- UVa 1602 Lattice Animals
- uva 1602 Lattice Animals
- UVa 1602:Lattice Animals(BFS)
- 【算法竞赛入门经典】7.7 回溯法求连通块 例题7-14 UVa1602
- Sklearn-GridSearchCV网格搜索