当前位置: 代码迷 >> 综合 >> 紫书 例题7-14 UVa 1602(搜索+STL+打表)
  详细解决方案

紫书 例题7-14 UVa 1602(搜索+STL+打表)

热度:110   发布时间:2023-09-20 22:28:24.0

这道题想了很久不知道怎么设置状态,怎么拓展,怎么判重, 最后看了这哥们的博客 终于明白了。

https://blog.csdn.net/u014800748/article/details/47400557


这道题的难点在于怎么设置联通的状态,以及怎么拓展判重 .


(1)状态:这里状态先定义了一个格子cell, 有x和y坐标。然后set<cell>表示一个联通块, 再用set<set<cell>>表示n个连块可以组成的所有联通块, 这里是集合套集合。 


(2)拓展:每个格子向四个方向拓展。平移方面用到了标准化,感性的认识就是把这个图形整个移到了左下角(具体看代码), 然后旋转,这里有一个规律,就是所有的格子都是 (x, y) -> (y, -x) ,每次执行都会旋转90度,记得最后返回的是标准化后的图形。翻转的话,沿x轴翻转, 即(x, y)-> (x, -y), 然后再旋转四次,其中旋转180度后即是y轴翻转的结果,已经包含在里面了,所以不用另外写。 


    (3)最后就是打表,在多组数据而每组数据程序运行的时候会做重复的事情的时候,用打表会比直接做更快一些 


代码如下

#include<cstdio>
#include<algorithm>
#include<set>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;struct cell
{int x, y;cell(int x = 0, int y = 0) : x(x), y(y) {}bool operator < (const cell& rhs) const{return x < rhs.x || (x == rhs.x && y < rhs.y); //固定写法 }
};const int MAXN = 11;
typedef set<cell> piece;
int ans[MAXN][MAXN][MAXN];
set<piece> poly[MAXN];
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};inline piece normalize(piece p0)
{int minx = 15, miny = 15; //最大也就10,这里表示最大值 for(auto& t : p0){minx = min(minx, t.x);miny = min(miny, t.y);}piece ret;for(auto& t : p0) ret.insert(cell(t.x - minx, t.y - miny)); //这种遍历方式要c++11, 编译选项要加入-std=c++11 return ret;
}inline piece rotate(piece p0)
{piece ret;for(auto& t : p0) ret.insert(cell(t.y, -t.x));return normalize(ret);
}inline piece file(piece p0)
{piece ret;for(auto& t : p0) ret.insert(cell(t.x, -t.y));return normalize(ret);
}void add(piece p0, cell c)
{piece p = p0;p.insert(c);p = normalize(p);int id = p.size();REP(i, 0, 4){if(poly[id].count(p)) return;p = rotate(p);}p = file(p);REP(i, 0, 4){if(poly[id].count(p)) return;p = rotate(p);}poly[id].insert(p);
}void work()
{piece start;start.insert(cell(0, 0));poly[1].insert(start);REP(n, 2, MAXN)for(auto& p : poly[n-1]) // 这里n-1,因为是从前一个拓展过来的 for(auto& t : p)REP(i, 0, 4){cell temp(t.x + dir[i][0], t.y + dir[i][1]);if(!p.count(temp)) add(p, temp);}REP(n, 1, MAXN)REP(w, 1, MAXN)REP(h, 1, MAXN){int cnt = 0;for(auto& p : poly[n]){int maxx = 0, maxy = 0;for(auto & t : p){maxx = max(maxx, t.x);maxy = max(maxy, t.y);}if(max(maxx, maxy) < max(w, h) && min(maxx, maxy) < min(w, h)) cnt++; //是否符合题目要求 }ans[n][w][h] = cnt;}
}int main()
{work();int n, w, h;while(~scanf("%d%d%d", &n, &w, &h))printf("%d\n", ans[n][w][h]);  //提前打表 return 0;
}