原题链接: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