Maigc Cubes:2017 Works Application笔试

来源:互联网 发布:org.apache.xml jar包 编辑:程序博客网 时间:2024/05/19 08:41

给定一个M*M*M的魔方,和N个小魔方,将每一个小魔方融合到大魔方里(小魔方的大小不确定,但是一定小于大魔方),融合的部位将将加起来再对P取余,要求最后的结果一定是全部为0。求出所有小魔方的位置。

思路如下,这个题目似乎没有找到巧妙的解法,所以采用暴力搜索.但是搜索也是有技巧的,我思考之后发现:这个问题很适合双向BFS搜索加减枝。从最终状态全0出发,我们可以每次减去一个魔方的值然后取余(-1%3 = 2),这样可以从最终的状态逆推。

然后从起始状态开始进行状态拓展,这个没有什么好说的。

:因为要使用状态交集,所以我们必须要把状态用Map存起来,为什么是Map呢,因为还需要一个value来保存状态经过的路径(小魔方的位置序列).因为必须要将所有小魔方都放进去,所以搜索的层数是固定的,关键在于正反状态有交集的时时候是第(N/2)层。

:假设现在有M个的位置不是0,同时剩下的所有小魔方一共有S个元素,那么M>S的时候就应该被剪掉。这个很好理解。同理反向剪枝是针对与初始状态有多少个不同的位置来计算的,同样的剪枝手段。

Python实现如下:

def check(i,j,bound):    return i+j>=bounddef zeros_tuple(M):    return tuple((tuple((0,)*M for i in range(M))) for j in range(M))def zeros_list(M):    return [[[0]*M for i in range(M)] for j in range(M)]def do(big,small,p,P,flag):    i,j,k = p    length = len(small)    res = [[list(v2) for v2 in v1] for v1 in big ]    for l1 in range(length):        for l2 in range(length):            for l3 in range(length):                _i,_j,_k = i+l1,j+l2,k+l3                res[_i][_j][_k] = (res[_i][_j][_k]+flag*small[l1][l2][l3])%P    return Tuple(res)def merge(big,small,p,P,pp = False):    return do(big,small,p,P,1)def recover(big,small,p,P):    return do(big,small,p,P,-1)def Tuple(vec):    return tuple(tuple(tuple(v2) for v2 in v1) for v1 in vec)def compute(big,P=0):    cnt = 0    for v1 in big:        for v2 in v1:            for v3 in v2:                if v3!=0:cnt+=1    return cntdef compute2(big,big_cube):    cnt = 0    for i,v1 in enumerate(big):        a = big_cube[i]        for j,v2 in enumerate(v1):            b = a[j]            for k,v3 in enumerate(v2):                if v3!=b[k]:cnt+=1    return cntdef bi_bfs(M,N,P,big_cube,s_cubes,count):    All_0 = zeros_tuple(M)     State1,State2 = {big_cube:[]},{zeros_tuple(M):[]}#initial state    c1,c2 = count,count    num = 0    for num in range(N):        next1,next2 = {},{}        small_cube1 = s_cubes[num]        small_cube2 = s_cubes[N-num-1]        len1 = len(small_cube1)        len2 = len(small_cube2)        c1 -= len1**3        c2 -= len2**3        for big_cube_tmp1,pos in State1.items():            for i in range(M):                if check(i,len1-1,M):break                for j in range(M):                    if check(j,len1-1,M):break                    for k in range(M):                        if check(k,len1-1,M):break                        s = merge(big_cube_tmp1,small_cube1,(i,j,k),P)                        remain = compute(s,P)                        if remain>c1:                            continue                        next1[s] = pos+[(i,j,k)]                        #if s in State2:print('zeros2');return next1[s]+State2[s][::-1]                        if num>=N-2-num and s in State2:print('zeros2');return next1[s]+State2[s][::-1]        for big_cube_tmp2,pos in State2.items():            for i in range(M):                if check(i,len2-1,M):break                for j in range(M):                    if check(j,len2-1,M):break                    for k in range(M):                        if check(k,len2-1,M):break                        s = recover(big_cube_tmp2,small_cube2,(i,j,k),P)                        remain = compute2(s,big_cube)                        if remain > c2:                            continue                        next2[s] = pos+[(i,j,k)]                        if  s in next1:print('zeros3');return next1[s]+next2[s][::-1]#return pos path                        if num>=N-2-num and s in next1:print('zeros3');return next1[s]+next2[s][::-1]#return pos path        State1,State2 = next1,next2        print(num,len(State1),len(State2))        print(num,len(State1)*(M-N+1)**3,len(State2)*(M-N+1)**3)def process():    M,N,P = map(int,input().split(' '))    vec = list(map(int,input().split(' ')))    big = zeros_list(M)    for ind,each in enumerate(vec):        _k,_j,_i = ind%M,(ind//M)%M,(ind//(M**2))%M        big[_i][_j][_k] = each    small_cubes = []    count = 0    for i in range(N):        vec = list(map(int,input().split(' ')))        n,vec = vec[0],vec[1:]        small = zeros_list(n)        for ind,each in enumerate(vec):            _k,_j,_i = ind%M,(ind//M)%M,(ind//(M**2))%M            small[_i][_j][_k] = each        count+=n**3        small_cubes.append(small)    p = bi_bfs(M,N,P,Tuple(big),small_cubes)    for line in p:        for i in line:            print(i,end = ' ')        print()###用来生成测试数据,不是正式代码def Test():    import random    M =8    N = 5    P = 10    b = zeros_list(M)    pos = [(7,7,7),(3,3,4),(3,3,1),(4,2,1),(3,2,1),(2,6,0),(5,1,1),(4,1,1),(5,6,3),(1,5,2)]    num = [1,2,3,4,5,6,7,8,9,2,1]    vec = [1,2,1,3,2,1,2,3,2,1,2,2]    smalls = []    count=0    for i in range(N):        n = vec[i]        small = zeros_list(n)        for v1 in small:            for v2 in v1:                 for k in range(n):                    v2[k] = num[i]#random.randint(0,P-1)        smalls.append(small)        count+=n**3        b = recover(b,small,pos[i],P)    #print(b)    print()    ps = bi_bfs(M,N,P,b,smalls,count)    print(ps)    for i,small in enumerate(smalls):        b = merge(b,small,ps[i],P,True)    assert(b == zeros_tuple(M))

C++实现:

#include <iostream>#include <vector>#include <algorithm>#include <unordered_map>#include <functional>using namespace std;struct pos {  short i;  short j;  short k;};class vector_hasher {public:  size_t operator()(vector<short> const& vec) const {    std::size_t ret = 0;    for(size_t i = 0; i!=vec.size(); ++i) {      ret ^= std::hash<short>()(vec[i]);    }    return ret;  }};typedef unordered_map<vector<short>, vector<pos>, vector_hasher> State;size_t M, N, P;vector<short> length;vector<short> big_cube;vector<vector<short> > small_cube;vector<short> operate(vector<short>& cube, vector<short>& small_cube, size_t length, pos& position, short flag) {  size_t m = position.i;  size_t n = position.j;  size_t p = position.k;  vector<short> new_cube = cube;  for (size_t i = 0; i < length; ++i) {    for (size_t j = 0; j < length; ++j) {      for (size_t k = 0; k < length; ++k) {        new_cube[M * M * (i + m) + M * (j + n) + (k + p)] += flag * small_cube[length * length * i + length * j + k];        if (new_cube[M * M * (i + m) + M * (j + n) + (k + p)] < 0) {          new_cube[M * M * (i + m) + M * (j + n) + (k + p)] += P;        }        new_cube[M * M * (i + m) + M * (j + n) + (k + p)] = new_cube[M * M * (i + m) + M * (j + n) + (k + p)] % P;      }    }  }  return new_cube;}vector<short> merge(vector<short>& cube, vector<short>& small_cube, size_t length, pos& position) {  return operate(cube, small_cube, length, position, 1);}vector<short> split(vector<short>& cube, vector<short>& small_cube, size_t length, pos& position) {  return operate(cube, small_cube, length, position, -1);}bool check(size_t i, size_t j) {  return i + j > M;}size_t count_zeros(vector<short>& inter) {  size_t count = 0;  for (size_t i = 0; i < M * M * M; ++i) {    if (inter[i] != 0) {      ++count;    }  }  return count;}size_t inverse_count(vector<short>& inter) {  size_t count = 0;  for (size_t i = 0; i < M * M * M; ++i) {    if (inter[i] != big_cube[i]) {      ++count;    }  }  return count; }vector<pos> bi_bfs(void) {  vector<short> all_zeros(M * M * M, 0);  State state_1, state_2;  state_1.insert(pair<vector<short>, vector<pos> >(big_cube, vector<pos>()));  state_2.insert(pair<vector<short>, vector<pos> >(all_zeros, vector<pos>()));  size_t count = 0;  for (size_t i = 0; i < N; ++i) {    count += length[i] * length[i] * length[i];  }  size_t c1 = count;  size_t c2 = count;  for (size_t num = 0; num < N; ++num) {    State next_1, next_2;    vector<short> small_1 = small_cube[num];    vector<short> small_2 = small_cube[N - num - 1];    size_t length_1 = length[num];    size_t length_2 = length[N - num - 1];    c1 -= length_1 * length_1 * length_1;    c2 -= length_2 * length_2 * length_2;    for (State::iterator iter = state_1.begin(); iter != state_1.end(); ++iter) {      vector<short> cube = iter->first;      vector<pos> path = iter->second;      for (size_t i = 0; i < M * M * M; ++i) {        size_t p = i % M;        size_t n = (i / M) % M;        size_t m = (i / (M * M)) % M;        if (check(m, length_1) || check(n, length_1) || check(p, length_1)) {             continue;        }        pos position;        position.i = m;        position.j = n;        position.k = p;        vector<short> new_cube = merge(cube, small_1, length_1, position);        size_t remain = count_zeros(new_cube);        if (remain > c1) {          continue;        }        path.push_back(position);        next_1.insert(pair<vector<short>, vector<pos> >(new_cube, path));        if (num >= N - num - 1 && state_2.find(new_cube) != state_2.end()) {          vector<pos> inverse_path = state_2[new_cube];          vector<pos> tmp = next_1[new_cube];          tmp.insert(tmp.end(), inverse_path.rbegin(), inverse_path.rend());          return tmp;        }      }    }    for (State::iterator iter = state_2.begin(); iter != state_2.end(); ++iter) {      vector<short> cube = iter->first;      vector<pos> path = iter->second;      for (size_t i = 0; i < M * M * M; ++i) {        size_t p = i % M;        size_t n = (i / M) % M;        size_t m = (i / (M * M)) % M;        if (check(m, length_2) || check(n, length_2) || check(p, length_2)) {          continue;        }        pos position;        position.i = m;        position.j = n;        position.k = p;        vector<short> new_cube = split(cube, small_2, length_2, position);        size_t remain = inverse_count(new_cube);        if (remain > c2) {          continue;        }        path.push_back(position);        next_2.insert(pair<vector<short>, vector<pos> >(new_cube, path));        if (num >= N - num - 1 && next_1.find(new_cube) != next_1.end()) {          vector<pos> inverse_path = next_2[new_cube];          vector<pos> tmp = next_1[new_cube];          tmp.insert(tmp.end(), inverse_path.rbegin(), inverse_path.rend());          return tmp;        }      }    }  state_1 = next_1;  state_2 = next_2;  }}int main() {  cin >> M >> N >> P;  big_cube.resize(M * M * M);  small_cube.resize(N);  length.resize(N);  vector<pos> position;  for (size_t i = 0; i < M * M * M; ++i) {    cin >> big_cube[i];  }  for (size_t i = 0; i < N; ++i) {    cin >> length[i];    size_t l = length[i];    small_cube[i].resize(l * l * l);    for (size_t j = 0; j < l * l * l; ++j) {      cin >> small_cube[i][j];    }  }  position = bi_bfs();  for (size_t i = 0; i < position.size(); ++i) {    pos p = position[i];    cout << p.i << " " << p.j << " " << p.k << endl;  }  return 0;}
0 0