这也是黑书上的一道例题。
先给个soj的链接:题目
【题目大意】
给定n*n(N<=5)个方块,每个方块由上下左右四个面构成。
问是否能将n*n个方块拼成任意两个相邻块的相邻面值相等。
实例如下图:
这是一个初始2*2的方块:
它可以拼成如下图形,满足要求:
分析:
这是个典型的搜索问题,属于约束性搜索。
搜索顺序从中间到两边能够比较快的剪掉一些枝。这里用bfs先计算出一个序列,再按照这个序列进行搜索。
由于可能存在完全相同的块,这里存储不同的块和每一块的数量。
通过dfs即可算出。
实事证明还是从头开始搜比较快= =
附个中间搜的代码如下:
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 32 ;
int num , cnt[maxn] , nn , n , path[maxn] , order[maxn][6] , boundary[maxn][6] , sth ;
bool vis[maxn] ;
struct node {
int top , right , bottom , left ;
}block[maxn];
inline bool get(int &t)
{
bool flag = 0 ;
char c;
while(!isdigit(c = getchar())&&c!='-') if( c == -1 ) break ;
if( c == -1 ) return 0 ;
if(c=='-') flag = 1 , t = 0 ;
else t = c ^ 48;
while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + (c ^ 48) ;
if(flag) t = -t ;
return 1 ;
}
void dosth(int k)
{
queue<int> q;
q.push(k/2*k);
int x , y , i = 0 ;
memset(vis,0,sizeof(vis));
while (!q.empty())
{
boundary[i][k] = 0 ;
x = order[i][k] = q.front(); q.pop();
if(vis[x]) continue;
vis[x] = 1 ;
if( x >= k ) q.push(x-k),boundary[i][k]^=1;
if( x % k != 0 ) q.push(x-1),boundary[i][k]^=2;
if( x % k != k-1 ) q.push(x+1),boundary[i][k]^=4;
if( x / k < k-1 ) q.push(x+k),boundary[i][k]^=8;
i++;
}
}
void init()
{
for( int i = 1 ; i <= 5 ; i++) dosth(i);
}
bool dfs(int pos)
{
if( pos == nn ) return true ;
for ( int i = 1 ; i < num ; i++) if( cnt[i] )
{
if( boundary[pos][n] & 1 && path[order[pos][n]-n] && block[path[order[pos][n]-n]].bottom != block[i].top ) continue;
if( boundary[pos][n] & 2 && path[order[pos][n]-1] && block[path[order[pos][n]-1]].right != block[i].left ) continue;
if( boundary[pos][n] & 4 && path[order[pos][n]+1] && block[path[order[pos][n]+1]].left != block[i].right ) continue;
if( boundary[pos][n] & 8 && path[order[pos][n]+n] && block[path[order[pos][n]+n]].top != block[i].bottom ) continue;
path[order[pos][n]] = i ;
cnt[i]--;
if(dfs(pos+1)) return 1 ;
cnt[i]++;
path[order[pos][n]] = 0 ;
}
return false ;
}
int main()
{
int t , k , i , j ;
init();
for ( k = 1 ; get(n) && n ; k++)
{
num = 1 ;
nn = n * n ;
sth = nn - n ;
for( i = 0 ; i < nn ; i++)
{
get(block[num].top); get(block[num].right); get(block[num].bottom); get(block[num].left);
for( j = 0 ; j < num ; j++)
if( block[num].top == block[j].top &&
block[num].bottom == block[j].bottom &&
block[num].right == block[j].right &&
block[num].left == block[j].left )
break;
if( j == num ) cnt[num++] = 1 ;
else cnt[j]++;
}
memset(path,0,sizeof(path));
if(dfs(0)) printf("Game %d: Possible\n\n",k);
else printf("Game %d: Impossible\n\n",k);
}
}
在附个zoj1008的代码
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 232 ;
int num , cnt[maxn] , nn , n , path[maxn] ;
bool vis[maxn] ;
struct node {
int top , right , bottom , left ;
}block[maxn];
inline bool get(int &t)
{
bool flag = 0 ;
char c;
while(!isdigit(c = getchar())&&c!='-') if( c == -1 ) break ;
if( c == -1 ) return 0 ;
if(c=='-') flag = 1 , t = 0 ;
else t = c ^ 48;
while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + (c ^ 48) ;
if(flag) t = -t ;
return 1 ;
}
const int cx[] = {1,-1,0,0};
const int cy[] = {0,0,1,-1};
bool dfs(int pos)
{
if( pos == nn ) return true ;
int x = pos / n ;
int y = pos % n ;
for ( int i = 0 ; i < num ; i++) if( cnt[i] )
{
if( x && block[path[pos-n]].bottom != block[i].top ) continue;
if( y && block[path[pos-1]].right != block[i].left ) continue;
path[pos] = i ;
cnt[i]--;
if(dfs(pos+1)) return 1 ;
cnt[i]++;
}
return false ;
}
int main()
{
int t , k , i , j ;
for ( k = 1 ; get(n) && n ; k++)
{
num = 0 ;
nn = n * n ;
for( i = 0 ; i < nn ; i++)
{
get(block[num].top); get(block[num].right); get(block[num].bottom); get(block[num].left);
for( j = 0 ; j < num ; j++)
if( block[num].top == block[j].top &&
block[num].bottom == block[j].bottom &&
block[num].right == block[j].right &&
block[num].left == block[j].left )
break;
if( j == num ) cnt[num++] = 1 ;
else cnt[j]++;
}
bool ff = dfs(0);
if(k>1)
puts("");
cout<<"Game "<<cases++<<": ";
if(ff)
cout<<"Possible"<<endl;
else cout<<"Impossible"<<endl;
}
}