• 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
    
  • 相关阅读:
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    64位WIN7系统 下 搭建Android开发环境
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
  • 原文地址:https://www.cnblogs.com/withhope/p/10497478.html
Copyright © 2020-2023  润新知