defcheck(i,j,bound):return i+j>=bound
defzeros_tuple(M):return tuple((tuple((0,)*M for i in range(M))) for j in range(M))
defzeros_list(M):return [[[0]*M for i in range(M)] for j in range(M)]
defdo(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)
defmerge(big,small,p,P,pp = False):return do(big,small,p,P,1)
defrecover(big,small,p,P):return do(big,small,p,P,-1)
defTuple(vec):return tuple(tuple(tuple(v2) for v2 in v1) for v1 in vec)
defcompute(big,P=0):
cnt = 0for v1 in big:
for v2 in v1:
for v3 in v2:
if v3!=0:cnt+=1return cnt
defcompute2(big,big_cube):
cnt = 0for 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+=1return cnt
defbi_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 = 0for 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**3for big_cube_tmp1,pos in State1.items():
for i in range(M):
if check(i,len1-1,M):breakfor j in range(M):
if check(j,len1-1,M):breakfor 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):breakfor j in range(M):
if check(j,len2-1,M):breakfor 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 pathif 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)
defprocess():
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 = 0for 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()
###用来生成测试数据,不是正式代码defTest():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=0for 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>usingnamespacestd;
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;
}
};
typedefunordered_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;
}
return0;
}