UVA 1602 Lattice Animals 回溯搜索

版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/83871234

原题链接

求w(10)*h(10)的网格内不同的n(10)连块的个数(不同是指不能通过平移,旋转,翻转得到).
(这种连块学名叫做Polyomino,有很多有趣的性质,俄罗斯方块中所有的块都是4连块)

情况有限,可以先搜索再打表。

搜索需要解决以下问题:

  1. 如何表示一种连块?连块的本质是若干个块位置的集合,所以可以使用set<pair<int,int>>来表示一种连块,把这个类型记为Poly.
  2. 如何在搜索过程中扩展?维护一个当前可添加的方块列表,每次扩展时从中选择一个,然后更新这个列表。
  3. 如何判重?使用一个set<Poly>来存储已经发现的所有连块及它们的平移,旋转,翻转。这样当发现一个新连块时,它不在set里时就表明它是没有重复的。
  4. 平移,旋转,翻转如何进行?有一个简洁的方法:初始位置从(0,0)开始,且连块的每次扩展都在第一象限内,这样就保证了所有连块都是紧贴坐标轴的,免去了平移的麻烦。如果记当前连块的最大行是rm,最大列是cm,那么沿横轴翻转后的Poly每个小方块坐标会从(r,c)变成(rm-r,cm),顺时针旋转90°之后会变成(cm-c,r).

一个省略了细节的实现:

const int M = 20;
const int go[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
using Coll = set<pair<int,int>>;
struct Poly
{
	Coll st; 
	int r, c; //0到r,0到c,闭区间
	bool operator<(const Poly &b) const{
		return st<b.st;
	}
	Poly rotate() {}
	Poly flip() {}
	void insert(int _r,int _c)
	{
		r = max(r,_r);
		c = max(c,_c);
		st.emplace(_a,_b);
	}
	void print() {} //输出图像,方便调试
};

int table[M][M][M];
set<Poly> st;
//不可递归情况:已经存在,或者长度为10
inline bool limit(const Poly &su) {}
inline void update(const Poly &su) {}
void dfs(const Poly &u, const Coll &un)
{
	if(limit(u)) return;
	update(u);
	for(auto pii:un)
	{
		Poly v = u; Coll vn = un; 
		int r = pii.first, c = pii.second;
		v.insert(r,c); vn.erase(pii);
		for(int k=0;k<4;++k)
		{
			int nr = r+go[k][0], nc = c+go[k][1];
			if(nr>=0 && v.st.count({nr,nc})==0)
				vn.emplace(nr,nc);
		}
		dfs(v,vn);
	}
}
int main(void)
{
	dfs(Poly(),Coll({{0,0}}));
	int n,w,h;
	while(scanf("%d%d%d",&n,&w,&h)!=EOF)
	{
		if(w<h) swap(w,h);
		printf("%d\n",table[n][w][h] );
	}
    return 0;
}

可以仔细地研究一下上边的代码。但实际上,它是错的:下方的的这种连块,它永远也无法回溯得到。

**
 ***

因为它在得到

**
 *

之前就已经得到过

**
*

了,判重之后不会再向外扩展。

正确的做法应当把第一个块放在地图的中央(比如10,10),然后向四周扩展。判重时先平移到紧靠坐标轴再判重。以下是完整代码。

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 20;
const int go[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
using Coll = set<pair<int,int>>;
struct Poly
{
	Coll st; 
	int l, r, u, d; 
	Poly(int _l = 10,int _r = 0, int _u = 10, int _d = 0)
		: l(_l),r(_r),u(_u),d(_d){}
	bool operator<(const Poly &b) const{
		return st<b.st;
	}
	Poly stand() const
	{
		Poly res;
		for(auto pii:st)
			res.insert(pii.first-u,pii.second-l);
		return res;
	}
	Poly rotate() const
	{
		Poly res;
		for(auto pii:st)
			res.insert(r-pii.second,pii.first);
		return res;
	}
	Poly flip() const
	{
		Poly res;
		for(auto pii:st)
			res.insert(d-pii.first,pii.second);
		return res;
	}
	void insert(int _a,int _b)
	{
		st.emplace(_a,_b);
		l = min(l,_b);
		r = max(r,_b);
		u = min(u,_a);
		d = max(d,_a);
	}
	void print() const
	{
		system("cls");
		char mp[M][M];
		memset(mp,'.',sizeof(mp));
		for(auto pii:st)
			mp[pii.first][pii.second]='*';
		for(int i=0;i<M;++i)
		{
			for(int j=0;j<M;++j)
				putchar(mp[i][j]);
			printf("\n");
		}
		printf("\n");
	}
};

set<Poly> st;
int table[M][M][M];
//不可递归情况:已经存在,或者长度为10
inline bool limit(const Poly &su)
{
	int n = su.st.size();
	if(!n) return 0;

	Poly u = su.stand();
	if(st.count(u)) return 1;
	//u.print();
	for(int i=0;i<4;++i)	
	{
		st.insert(u);
		st.insert(u.flip());
		u = u.rotate();
	}

	int mi = min(u.d,u.r), ma = max(u.d,u.r);
	for(int i=ma+1;i<=n;++i) //大
		for(int j=mi+1;j<=i;++j) //小
			++table[n][i][j];

	return n==10;
}
void dfs(const Poly &u, const Coll &un)
{
	if(limit(u)) return;
	for(auto pii:un)
	{
		Poly v = u; Coll vn = un; 
		int r = pii.first, c = pii.second;
		v.insert(r,c); vn.erase(pii);
		for(int k=0;k<4;++k)
		{
			int nr = r+go[k][0], nc = c+go[k][1];
			if(nr>=0 && v.st.count({nr,nc})==0)
				vn.emplace(nr,nc);
		}
		dfs(v,vn);
	}
}
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	dfs(Poly(),Coll({{10,10}}));
	int n,w,h;
	while(scanf("%d%d%d",&n,&w,&h)!=EOF)
	{
		if(w<h) swap(w,h);
		printf("%d\n",table[n][w][h] );
	}
    return 0;
}


inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/83871234