Maigc Cubes:2017 Works Application筆試

給定一個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>=bound
def 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 cnt
def 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 cnt

def 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;
}
發佈了366 篇原創文章 · 獲贊 62 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章