Topcoder 10524(SRM451 Div.1 C) BrickPuzzle题解

原题链接:Topcoder 10524(SRM451 Div.1 C) BrickPuzzle
Virtual Judge链接:Topcoder 10524(SRM451 Div.1 C) BrickPuzzle
题目大意:给定一个(n imes m(1leq n,m leq 22 ))的矩阵,矩阵中有白块和黑块,你的目标是用4种块将矩阵中的所有白块覆盖,且每一个覆盖上去的块不得与其他块重合(可以在黑块上放),求最少需要多少个块,若无论如何都覆盖不了,输出(-1)。四个块的图四个块的图
题解:
这道题很容易想到状态压缩+动规,正解也是这样,开始口胡:
首先,我们记录一下到了第((x,y))个点,之前的已经摆满了,上面1行加上2个的状态时摆完接下来的最少块数,然后记忆化搜索+map就可以了。
口胡完毕。
下面的题解太长了,总结就放这吧
总结:对于这一种题,首先肯定要考虑暴力dfs+剪枝能不能过,因为这一种情况一般不会写错。但这一道题很明显是会超时的,那么就会想到状态压缩,状态压缩的时候也会有很多种情况,尤其是在分类讨论是否已经摆满了,可不可以继续往下走时,这种情况下一定要小心,一个又一个的if语句很容易写错,还有一点,就是数组不能乱开,一开始数组开大了,MLE但却返回了WA让我调了很久,下次再也不能乱开数组了。
接下来来看各路神仙的代码:
fan haoqiang

#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
#define NMax 22
#define HMax 1000003
struct state {
	int x,y,s,c;
	state *next,*succ;
};//用链表记录前去后继
class BrickPuzzle {
	public:
		int N,M;
		bool Map[NMax][NMax];
		state* getnew(state *p=NULL) {
			static state* list=NULL;
			if (p) {
				p->next=list;
				list=p;
			} else {
				if (!list) {
					state *q=new state[10000];
					for (int i=0; i<10000; i++) {
						q[i].next=list;
						list=q+i;
					}
				}
				p=list;
				list=list->next;
				return p;
			}
			return NULL;
		}//寻找后继
		state* head[NMax][NMax],*tail[NMax][NMax];
		state* hash[HMax];
		int ret;
		int hashcode(int x,int y,int s) {
			int k=s+(x<<27)+(y<<22);
			k%=HMax;
			if (k<0)k+=HMax;
			return k;
		}
		void giveback(state *q) {
			int h=hashcode(q->x,q->y,q->s);
			for (state **p=&(hash[h]);; p=&((*p)->succ)) {
				if ((*p)==q) {
					(*p)=q->succ;
					break;
				}
			}
			getnew(q);
		}
		void inQ(int x,int y,int tp,int bt,int c) {
			//while (y<M && (tp&(1<<y)))y++;
			y=__builtin_ctz(~(tp>>y))+y;
			while (y==M) {
				if (x==N-1) {
					ret=min(ret,c);
					return;
				}
				tp=bt;
				bt=0;
				x++;
				y=0;
				y=__builtin_ctz(~(tp>>y))+y;
				//while (y<M && (tp&(1<<y)))y++;
			}
			int s=(tp&~((1<<(y+1))-1))|(bt&((1<<(y+1))-1));
			int h=hashcode(x,y,s);
			state **p=&(hash[h]);
			while ((*p) && ((*p)->x!=x || (*p)->y!=y || (*p)->s!=s))
				p=&((*p)->succ);
			if (!(*p)) {
				state *q=(*p)=getnew();
				q->x=x;
				q->y=y;
				q->s=s;
				q->c=c;
				q->succ=NULL;
				q->next=NULL;
				if (!head[x][y])head[x][y]=q;
				else tail[x][y]->next=q;
				tail[x][y]=q;
			} else {
				if ((*p)->c>c)(*p)->c=c;
			}
		}//转移
		int leastShapes(vector<string> board) {
			N=board.size();
			M=board[0].length();
			for (int i=0; i<N; i++)for (int j=0; j<M; j++)
					Map[i][j]=(board[i][j]=='.');
			memset(hash,0,sizeof(hash));
			memset(head,0,sizeof(head));
			memset(tail,0,sizeof(tail));
			ret=~0u>>1;
			inQ(0,0,0,0,0);
			for (int x=0; x<N; x++)for (int y=0; y<M; y++) {
					while (head[x][y]) {
						state *p=head[x][y];
						head[x][y]=head[x][y]->next;
						int c=p->c,s=p->s;
						int bt=s&((1<<(y+1))-1),tp=s&~((1<<(y+1))-1);
						//do nothing
						if (!Map[x][y]) {
							inQ(x,y+1,tp,bt,c);
						}
						//*###
						if (y+3<M && !(tp&(15<<y))) {
							inQ(x,y+4,tp|(15<<y),bt,c+1);
						}
						//*#
						//##
						if (x+1<N && y+1<M && !(tp&(3<<y))
						        && !(bt&(3<<y))) {
							inQ(x,y+2,tp|(3<<y),bt|(3<<y),c+1);
						}
						//*#
						// ##
						if (x+1<N && y+2<M && !(tp&(3<<y))
						        && !(bt&(6<<y))) {
							inQ(x,y+2,tp|(3<<y),bt|(6<<y),c+1);
						}
						// *#
						//##
						if (x+1<N && y-1>=0 && y+1<M && !(tp&(3<<y))
						        && !(bt&(3<<(y-1)))) {
							inQ(x,y+2,tp|(3<<y),bt|(3<<(y-1)),c+1);
						}
						giveback(p);
					}
				}//动态规划
			if (ret==(~0u>>1))ret=-1;
			return ret;
		}
} me;
int main() {
	char *a[]=
	{"...X.X..XX..XXX..XX.XX", "..X...XXXX.....X..XX.X", "X.X..X.X..XX.XX..XX.X.", ".XX..X...X.XX..X..XXX.", "X..X...X.X....X.....X.", ".XXXX.XX.........X.X..", ".XX..X.X.XX.X.X.XXXXXX", "X.X.X.X.XXXX.XXXX.XX.X", "..XXX....X..XX..XX.X..", ".X.X.XX....XX..XXX..X.", "...XXX.XX..XXX...XXXXX", "X.X.XX.X.XXX.XXXXX.X..", "..X...X...X.X.XXXXXX.X", "X.X.XXX.X.X.XX.....XXX", "X..XX....X..X.XX.XX..X", "XX.X.X......XX.X....X.", "...XX..X.X.X..XXX..XX.", ".X...X..X.X..X....X.X.", "..X..XX.X...X....X.XX.", "XX...X.X.X.X.XXX...X.X", "X.X....X.XX...X..XXX..", "...XX.XXXXX.X...XX.X.X"}
	;
	printf("%d
",me.leastShapes(vector<string> (a,a+sizeof(a)/sizeof(a[0]))));
	return 0;
}

zhou erjin
简洁

#include <bits/stdc++.h>
using namespace std;
char f[3][1<<22];
int q[3][1<<19];
int n,m,sign;
char key;
int r[3];
char g[55][55];
char *nf;
int *nq;
int cnt[1<<22];
class BrickPuzzle {
	public:
		inline void renew(int y) {
			if (!nf[y]) {
				nq[++nq[0]]=y;
				nf[y]=key;
			} else if (key<nf[y]) nf[y]=key; //[x][y]=min(f[x][y],z);
		}
		int leastShapes(vector <string> board) {
			//memset(cnt,0,sizeof(cnt));
			//memset(f,0,sizeof(f));
			n=board.size();
			m=board[0].size();
			f[0][0]=1;
			q[0][1]=0;
			q[0][0]=1;
			q[1][0]=q[2][0]=0;
			for (int i=0; i<(1<<m); i++)
				for (int j=0; j<m; j++)
					cnt[i]+=(i&(1<<j))>0;//有多少格未填
			for (int i=0; i<n; i++)
				for (int j=0; j<m; j++)
					g[i][j]=board[i][j];
			for (int i=0; i<n; i++)
				for (int j=0; j<m; j++) {
					int x=(i*m+j)%3;
					int y=(x+1)%3,z=(x+2)%3;
					int xxx=0;
					for (int k=0; k<j; k++)
						if (g[i][k]=='X') xxx+=(1<<k);
					if (i)
						for (int k=j; k<m; k++)
							if (g[i-1][k]=='X') xxx+=(1<<k);
					for (int l=q[x][0]; l; l--) {
						int state=q[x][l];
						key=f[x][state];
						f[x][state]=0;
						if (m>=20 && cnt[state&xxx]>4) continue;
						nf=f[y];
						nq=q[y];
						if (!(state&(1<<j)) && g[i][j]=='X')
							renew(state);
						nf=f[z];
						nq=q[z];
						if (state&(1<<j)) renew(state^(1<<j));
						else if (j+1<m) {
							key++;
							if (state&(1<<(j+1))) continue;
							if (j+3<m && !(state&(3<<(j+2))))
								renew(state^(4<<j));
							//if (i==n-1) continue;
							if (j+2<m) renew(state^(2<<j));
							renew(state^(1<<j));
							if (j==1  || (j>1 && !(state&(3<<(j-2))))) renew(state^(1<<(j-1)));
						}
					}//printf("%d
",q[x][0]);
					q[x][0]=0;
				}//动态规划+滚动数组
			return f[n*m%3][0]-1;
		}
};//以下非正题
// BEGIN KAWIGIEDIT TESTING
// Generated by KawigiEdit 2.1.4 (beta) modified by pivanof
bool KawigiEdit_RunTest(int testNum, vector <string> p0, bool hasAnswer, int p1) {
	cout << "Test " << testNum << ": [" << "{";
	for (int i = 0; int(p0.size()) > i; ++i) {
		if (i > 0) {
			cout << ",";
		}
		cout << """ << p0[i] << """;
	}
	cout << "}";
	cout << "]" << endl;
	BrickPuzzle *obj;
	int answer;
	obj = new BrickPuzzle();
	clock_t startTime = clock();
	answer = obj->leastShapes(p0);
	clock_t endTime = clock();
	delete obj;
	bool res;
	res = true;
	cout << "Time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " seconds" << endl;
	if (hasAnswer) {
		cout << "Desired answer:" << endl;
		cout << "	" << p1 << endl;
	}
	cout << "Your answer:" << endl;
	cout << "	" << answer << endl;
	if (hasAnswer) {
		res = answer == p1;
	}
	if (!res) {
		cout << "DOESN'T MATCH!!!!" << endl;
	} else if (double(endTime - startTime) / CLOCKS_PER_SEC >= 2) {
		cout << "FAIL the timeout" << endl;
		res = false;
	} else if (hasAnswer) {
		cout << "Match :-)" << endl;
	} else {
		cout << "OK, but is it right?" << endl;
	}
	cout << "" << endl;
	return res;
}
int main() {
	bool all_right;
	all_right = true;
	vector <string> p0;
	int p1;
	{
// ----- test 0 ----
		string t0[] = {"..X....","..XXXXX"};
		p0.assign(t0, t0 + sizeof(t0) / sizeof(t0[0]));
		p1 = 2;
		all_right = KawigiEdit_RunTest(0, p0, true, p1) && all_right;
// -----------------
	}
	{
// ----- test 1 ----
		string t0[] = {".X","..","X."};
		p0.assign(t0, t0 + sizeof(t0) / sizeof(t0[0]));
		p1 = -1;
		all_right = KawigiEdit_RunTest(1, p0, true, p1) && all_right;
// -----------------
	}
	{
// ----- test 2 ----
		string t0[] = {"..XX....","....X..X","XX..XXXX"};
		p0.assign(t0, t0 + sizeof(t0) / sizeof(t0[0]));
		p1 = 4;
		all_right = KawigiEdit_RunTest(2, p0, true, p1) && all_right;
// -----------------
	}
	{
// ----- test 3 ----
		string t0[] = {"X..XXXX","X.....X","....XX.","X......"};
		p0.assign(t0, t0 + sizeof(t0) / sizeof(t0[0]));
		p1 = 5;
		all_right = KawigiEdit_RunTest(3, p0, true, p1) && all_right;
// -----------------
	}
	if (all_right) {
		cout << "You're a stud (at least on the example cases)!"
		     << endl;
	} else {
		cout << "Some of the test cases had errors." << endl;
	}
	return 0;
}//此处都是测样例的,不用看
// END KAWIGIEDIT TESTING
//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!

wei min
同样的一个状态转移,也是用滚动数组优化空间。

#include <bits/stdc++.h>
using namespace std;
typedef vector<int> VI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long LL;
#define two(x) (1 << (x))
#define fill(x, y) memset((x), (y), sizeof(x))
template<class T> inline void checkmin(T &a, const T &b) {
	if (b < a) a = b;
}
template<class T> inline void checkmax(T &a, const T &b) {
	if (b > a) a = b;
}
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-7;
class BrickPuzzle {
	public:
		int leastShapes(vector <string> board);
// BEGIN CUT HERE
	public:
		void run_test(int Case) {
			if ((Case == -1) || (Case == 0)) test_case_0();
			if ((Case == -1) || (Case == 1)) test_case_1();
			if ((Case == -1) || (Case == 2)) test_case_2();
			if ((Case == -1) || (Case == 3)) test_case_3();
		}
	private:
		template <typename T> string print_array(const vector<T> &V) {
			ostringstream os;
			os << "{ ";
			for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '"' << *iter << "",";
			os << " }";
			return os.str();
		}
		void verify_case(int Case, const int &Expected, const int &Received) {
			cerr << "Test Case #" << Case << "...";
			if (Expected == Received) cerr << "PASSED" << endl;
			else {
				cerr << "FAILED" << endl;
				cerr << "	Expected: "" << Expected << '"' << endl;
				cerr << "	Received: "" << Received << '"' << endl;
			}
		}
		void test_case_0() {
			string Arr0[] = {"..X....",
			                 "..XXXXX"
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 2;
			verify_case(0, Arg1, leastShapes(Arg0));
		}
		void test_case_1() {
			string Arr0[] = {".X",
			                 "..",
			                 "X."
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = -1;
			verify_case(1, Arg1, leastShapes(Arg0));
		}
		void test_case_2() {
			string Arr0[] = {"..XX....",
			                 "....X..X",
			                 "XX..XXXX"
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 4;
			verify_case(2, Arg1, leastShapes(Arg0));
		}
		void test_case_3() {
			string Arr0[] = {"X..XXXX",
			                 "X.....X",
			                 "....XX.",
			                 "X......"
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 5;
			verify_case(3, Arg1, leastShapes(Arg0));
		}
// END CUT HERE
};
const int L[] = {0, 0, 0, -1};
const int R[] = {3, 2, 1, 1};
int m, n;
int f[3][two(18) + 5];
int bd[4];
int cidx;
int toidx[two(23) + 5];
int tomsk[two(18) + 5];
void update(map<int, int> &f, int x, int y) {
	if (f.count(x) == 0)
		f[x] = y;
	else
		checkmin(f[x], y);
}
int rev(int msk) {
	if (toidx[msk] == -1) {
		tomsk[cidx] = msk;
		toidx[msk] = cidx++;
	}
	return toidx[msk];
}
int BrickPuzzle::leastShapes(vector <string> board) {
	cidx = 0;
	m = board.size();
	n = board[0].size();
	bd[0] = 15;
	bd[1] = 1 + 2 + two(n + 1) + two(n + 2);
	bd[2] = 1 + 2 + two(n) + two(n + 1);
	bd[3] = 1 + 2 + two(n - 1) + two(n);
	int p0 = 0, p1 = 1, p2 = 2;
	fill(f, 0x3f);
	for (int i = 0; i < two(n + 1); ++i) toidx[i] = -1;
	checkmin(f[p0][rev(0)], 0);
	for (int i = 0; i < m; ++i) for (int j = 0; j < n; ++j) {
			for (int l = 0; l < cidx; ++l) {
				int x = tomsk[l];
				int y = f[p0][l];
				if (y == inf) continue;
				if (board[i][j] == 'X' || (x & 1)) checkmin(f[p1] [rev(x >> 1)], y);//update(f[p1], x >> 1, y);
				for (int k = 0; k < 4; ++k) if (j + L[k] >= 0 && j + R[k] < n && (x & bd[k]) == 0)
						checkmin(f[p2][rev((x | bd[k]) >> 2)], y + 1);
//update(f[p2], (x | bd[k]) >> 2, y + 1);
			}
			p0 = (p0 + 1) % 3;
			p1 = (p1 + 1) % 3;
			p2 = (p2 + 1) % 3;
			fill(f[p2], 0x3f);
		}
	int ans = f[p0][rev(0)];
	return ans == inf ? -1 : ans;
}
// BEGIN CUT HERE
int main() {
	BrickPuzzle ___test;
	___test.run_test(-1);
	system("pause");
}
// END CUT HERE

yang tian

#include <bits/stdc++.h>
using namespace std;
int n,m,f[2][30000],t,i,j,ans,g[30000],l,ag[1<<22];
const int md=1048575;
int h[md+1],xt[199997],v4[199997],tot;
int v3[199997];
int st[24],next[199997],d1[199997],d2[199997],ed;
int hs[199997];
vector <string> s;
struct BrickPuzzle {
	bool yf(int x,int y,int z) { //判断这个位置上能否放置这个物块
		if ( !((1<<(y-1)) & z) ) return true;
		return false;
	}
	bool bg(int x,int y,int z) { //判断这个位置如果此时不放物块是否可行
		if (s[x-1][y-1]=='X'|| ( (1<<(y-1))& z) ) return true;
		return false;
	}
	void del(int x) { //将多余元素进行回收下次再用
		int now=((d1[x]<<1)+(d2[x])+(v3[x]<<15))&md;
		int p=h[now];
		if (h[now]==x) h[now]=xt[h[now]];
		else {
			while (xt[p]!=x && p) p=xt[p];
			xt[p]=xt[xt[p]];
		}
		hs[++hs[0]]=x;
	}
	int rn(int bf,int nt,int w,int v) { //更新dp的状态
		if (w>1) {
			int fk=(1<<(w-1))-1;
			bf=(bf ^(fk &bf));
		}
		if (w>m) {
			if (f[t][ag[nt]]>v) f[t][ag[nt]]=v;
			return v;
		}
		int now=((bf<<1)+(nt)+(w<<15))&md;//hash来判断状态是否出现是 否最优并用链表存入状态
		int p=h[now];
		while (p) {
			if (d1[p]==bf && d2[p]==nt && v3[p]==w) {
				if (v<v4[p]) v4[p]=v;
				return v4[p];
			}
			p=xt[p];
		}
		if (hs[0]) { //使用回收的状态
			p=hs[hs[0]];
			hs[0]--;
			v3[p]=w;
			v4[p]=v;
			xt[p]=h[now];
			h[now]=p;
			d1[p]=bf;
			d2[p]=nt;
			next[p]=st[w];
			st[w]=p;
		} else {
			tot++;
			v3[tot]=w;
			v4[tot]=v;
			xt[tot]=h[now];
			h[now]=tot;
			ed++;
			d1[ed]=bf;
			d2[ed]=nt;
			next[ed]=st[w];
			st[w]=ed;
		}
		return v;
	}
	void renew(int bf,int nt,int w,int v) { //进行状态转移
		if (w>m) {
			if (v+f[1-t][j]<f[t][nt]) f[t][nt]=v+f[1-t][j];
		} else {
			//四种物块的转移
			{
				if (w+1<=m && (i-1))
					if (yf(i-1,w+1,bf)) {
						if (w+2<=m) {
							if (yf(i-1,w,bf))
								if (s[i-2][w]=='.' || s[i-1] [w]=='.' || s[i-2][w-1]=='.' || s[i-1][w+1]=='.')
									rn(bf|(1<<(w-1))|(1<<w),nt|(1<<w)|(1<<(w+1)),w+2,v+1);
							if (yf(i,w,nt) && yf(i-1,w+2,bf))
								if (s[i-2][w]=='.' || s[i-1] [w]=='.' || s[i-1][w-1]=='.' || s[i-2][w+1]=='.')
									if (bg(i-1,w,bf)) rn(bf|(1<<w)|(1<<(w+1)),nt|(1<<w)|(1<<(w-1)),w+2,v+1);
						}
						if (yf(i-1,w,bf) && yf(i,w,nt))
							if (s[i-2][w]=='.' || s[i-1] [w]=='.' || s[i-2][w-1]=='.' || s[i-1][w-1]=='.')
								rn(bf|(1<<(w-1))|(1<<w),nt|(1<<(w-1))|(1<<w),w+2,v+1);
					}
				if (w+3<=m)
					if (yf(i,w,nt))
						if ((i==1) || (bg(i-1,w,bf) &&
						               bg(i-1,w+1,bf) && bg(i-1,w+2,bf)))
							if (s[i-1][w-1]=='.' || s[i-1][w]=='.' || s[i-1][w+1]=='.' || s[i-1][w+2]=='.')
								rn(bf,nt|(1<<(w-1))|(1<<w)|(1<<(w+1))|(1<<(w+2)),w+3,v+1);
				if (i==1 || bg(i-1,w,bf)) rn(bf,nt,w+1,v);//空置的转移
			}
		}
	}
	void dfs(int x,int y) { //求出所有可行状态
		if (x<m) {
			dfs(x+1,y);
			dfs(x+2,y|(1<<(x-1))|(1<<x) );
		} else g[++g[0]]=y,ag[y]=g[0];
	}
	int leastShapes(vector <string> a) {
		s=a;
		n=s.size(),m=s[0].length(),t=0;
		dfs(1,0);
		memset(f,0x7f,sizeof f);
		f[0][1]=0;
		ans=100000;
		for (i=1; i<=n; i++) { //dp
			t=1-t;
			ed=0;
			memset(h,0,sizeof h);
			tot=0;
			hs[0]=0;
			for (l=0; l<=m; l++) st[l]=0;
			for (l=1,j=g[1]; l<=g[0]; l++,j=g[l])
				if (f[1-t][l]<100000)
					renew(j,0,1,f[1-t][l]);
			for (l=1; l<=m; l++) {
				int k=st[l];
				int dc=0;
				while (k) {
					renew(d1[k],d2[k],l,v4[k]);
					del(k);
					k=next[k];
					dc++;
				}
			}
			for (l=1; l<=g[0]; l++) f[1-t][l]=100000;
		}
		for (l=1,j=0; l<=g[0]; l++,j=g[l]) { //求出总答案
			bool fd=true;
			for (i=1; i<=m; i++)
				if (!bg(n,i,j)) fd=false;
			if (fd && f[t][l]<ans) {
				ans=f[t][l];
			}
		}
		if (ans>1000) return -1;
		else    return ans;
	}
};

jiang zhongtian
同样的状压做法,加上了hash之后变得极为难写,代码(有很长一段代码时测样例的):

using namespace std;
#define ME(s,a) memset((s),(a),sizeof((s)))
#define MM(s) memset((s),-1,sizeof((s)))
#define MCP(s,a) memcpy((s), (a), sizeof(s))
#define LL long long
#define PII pair<int, int>
#define mkp(a,b) make_pair((a),(b))
#define x first
#define y second
#define inf (999999999999999ll)
#define MAXN (800000)
struct node {
	int x,y,val;
	int mask;
	node *nxt;
	node(int _x=0,int _y=0,int _mask=0,int _val=0) {
		x=_x;
		y=_y;
		mask=_mask;
		nxt=NULL;
		val=_val;
	}
} STORE[MAXN];
#define MOD 249983
int n,m;
int ttt=0;
vector<string> a;
queue<node> Q;
struct hash_set {
	node *head[271111];
	void clear() {
		for (int i=0; i<MOD; i++) head[i]=NULL;
		ttt=0;
	}
	int add(node t,int val) {
		int cur=((t.mask*m+t.y)%MOD*n+t.x)%MOD;
		node *p=head[cur];
		while (p!=NULL) {
			if (p->x==t.x&&p->y==t.y&&p->mask==t.mask) {
				p->val=min(p->val,val);
				return 1;
			}
			p=p->nxt;
		}
		p=&STORE[ttt];
		ttt=(ttt+1)%MAXN;
		*p=t;
		p->val=val;
		p->nxt=head[cur];
		head[cur]=p;
		Q.push(t);
		return -1;
	}
	int find(node t) {
		int cur=((t.mask*m+t.y)%MOD*n+t.x)%MOD;
		node *p=head[cur];
		while (p!=NULL) {
			if (p->x==t.x&&p->y==t.y&&p->mask==t.mask) {
				return p->val;
			}
			p=p->nxt;
		}
		return 999999;
	}
	void del(node t) {
		int cur=((t.mask*m+t.y)%MOD*n+t.x)%MOD;
		node *p=head[cur],*prev=NULL;
		while (p!=NULL) {
			if (p->x==t.x&&p->y==t.y&&p->mask==t.mask) {
				if (prev!=NULL) prev->nxt=p->nxt;
				else head[cur]=p->nxt;
				return ;
			}
			prev=p;
			p=p->nxt;
		}
	}
} X;
void add(node cur) {
	X.add(cur,cur.val);
}
class BrickPuzzle {
	public:
		int leastShapes(vector <string> board) {
			X.clear();
			a=board;
			n=a.size();
			m=a[0].size();
			while (!Q.empty()) Q.pop();
			X.add(node(0,0,0,0),0);
			int ans=999999999;
			int rt=0;
			cout << clock() <<endl;
			while (!Q.empty()) {
				node cur=Q.front();
				Q.pop();
				cur.val=X.find(cur);
				X.del(cur);
				if (cur.x==n) {
					ans=min(ans,cur.val);
					continue;
				}
// add nothing
				if (a[cur.x][cur.y]=='X'||(cur.mask&1)==1)
					add(node(cur.x+(cur.y+1)/m,(cur.y+1)% m,(cur.mask>>1),cur.val));
// add ****
				if (cur.y+3<m&&(cur.mask&15)==0&&!(a[cur.x] [cur.y]=='X'&&a[cur.x][cur.y+1]=='X'&&a[cur.x][cur.y+2]=='X'&&a[cur.x] [cur.y+3]=='X'))
					add(node(cur.x+(cur.y+1)/m,(cur.y+1)% m,(cur.mask>>1)+7,cur.val+1));
// add **
//      **
				if (cur.y+2<m&&cur.x+1<n&&(cur.mask&3)==0 &&((cur.mask>>(m+1))&3)==0&&!(a[cur.x][cur.y]=='X'&&a[cur.x][cur.y+ 1]=='X'&&a[cur.x+1][cur.y+1]=='X'&&a[cur.x+1][cur.y+2]=='X'))
					add(node(cur.x+(cur.y+1)/m,(cur.y+1)% m,(cur.mask>>1)+1+(3<<(m)),cur.val+1));
// add  **
//     **
				if (cur.y>0&&cur.y+1<m&&cur.x+1<n&&(cur.mask&3)==0 &&((cur.mask>>(m-1))&3)==0&&!(a[cur.x][cur.y]=='X'&&a[cur.x][cur.y+ 1]=='X'&&a[cur.x+1][cur.y-1]=='X'&&a[cur.x+1][cur.y]=='X'))
					add(node(cur.x+(cur.y+1)/m,(cur.y+1)% m,(cur.mask>>1)+(3<<(m-2))+1,cur.val+1));
// add **
//     **
				if (cur.y+1<m&&cur.x+1<n&&(cur.mask&3)==0 &&((cur.mask>>m)&3)==0&&!(a[cur.x][cur.y]=='X'&&a[cur.x][cur.y+ 1]=='X'&&a[cur.x+1][cur.y]=='X'&&a[cur.x+1][cur.y+1]=='X'))
					add(node(cur.x+(cur.y+1)/m,(cur.y+1)% m,(cur.mask>>1)+(3<<(m-1))+1,cur.val+1));
			}
			if (ans>99999999) return -1;
			return ans;
		}
// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor
// BEGIN CUT HERE
// BEGIN CUT HERE
	public:
		void run_test(int Case) {
			if ((Case == -1) || (Case == 0)) test_case_0();
			if ((Case == -1) || (Case == 1)) test_case_1();
			if ((Case == -1) || (Case == 2)) test_case_2();
			if ((Case == -1) || (Case == 3)) test_case_3();
		}
	private:
		template <typename T> string print_array(const vector<T> &V) {
			ostringstream os;
			os << "{ ";
			for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '"' << *iter << "",";
			os << " }";
			return os.str();
		}
		void verify_case(int Case, const int &Expected, const int &Received) {
			cerr << "Test Case #" << Case << "...";
			if (Expected == Received) cerr << "PASSED" << endl;
			else {
				cerr << "FAILED" << endl;
				cerr << "	Expected: "" << Expected << '"' << endl;
				cerr << "	Received: "" << Received << '"' << endl;
			}
		}
		void test_case_0() {
			string Arr0[] = {"XXXXX.X..X..XXX......", ".XXX.X...X.X.X.X.X.X.", "X..XXXXXXX....XX.XXX.", ".XX....X..XX..XX.X.X.", ".XX..X............XXX", "XXX.......XX..XX.X.X.", "...X.X.XXXXXXX...X.X.", "X..XXXXX.X..XX.X.XXX.", ".XXX.XX.X.....X.XXXXX", "..XXXX.....X.X...X...", ".X.XX....XX..XX.XX..X", "XXX..X....XXX..X....X", ".XX.X..X..X.XXX..X.X.", "XX..X....X.XXXXXXXXXX", ".X.XX.XXXXX..X.X..XX.",
			                 "X...X.XX.XX..X.X...XX", "X.X.X....XXXXX.X.X.X.", "XXX.XXXXX.XXXXX....X.", ".X.XX...XXXXX.XX..XXX", ".X.XXX.X.XXXXX..XX...", "XX..X..XXX..X.XX.X.X."
			                }
			                ;
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 2;
			verify_case(0, Arg1, leastShapes(Arg0));
		}
		void test_case_1() {
			string Arr0[] = {".X",
			                 "..",
			                 "X."
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = -1;
			verify_case(1, Arg1, leastShapes(Arg0));
		}
		void test_case_2() {
			string Arr0[] = {"..XX....",
			                 "....X..X",
			                 "XX..XXXX"
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 4;
			verify_case(2, Arg1, leastShapes(Arg0));
		}
		void test_case_3() {
			string Arr0[] = {"X..XXXX",
			                 "X.....X",
			                 "....XX.",
			                 "X......"
			                };
			vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0])));
			int Arg1 = 5;
			verify_case(3, Arg1, leastShapes(Arg0));
		}
// END CUT HERE
// END CUT HERE
};
// BEGIN CUT HERE
#include<conio.h>
int main() {
	BrickPuzzle ___test;
	___test.run_test(-1);
	getch();
	return 0;
}
// END CUT HERE
原文地址:https://www.cnblogs.com/withhope/p/10497478.html