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

原题链接:Topcoder 10524(SRM451 Div.1 C) BrickPuzzle
Virtual Judge链接:Topcoder 10524(SRM451 Div.1 C) BrickPuzzle
题目大意:给定一个\(n\times m(1\leq 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\n",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\n",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 << "\t" << p1 << endl;
    }
    cout << "Your answer:" << endl;
    cout << "\t" << 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 << "\tExpected: \"" << Expected << '\"' << endl;
                cerr << "\tReceived: \"" << 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 << "\tExpected: \"" << Expected << '\"' << endl;
                cerr << "\tReceived: \"" << 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值