题目链接:
https://vjudge.net/problem/UVA-211
题意:
给一副图,代表多米诺骨牌摆放方式,每两个连成一块牌,如0 0 对应1号排 0 1 对应2号排,问图可以代表几种摆放方式。
题解:
dfs,每个位置的牌不是竖就是横,枚举2个方向,最多枚举28块,O(2^28),加个剪枝,如果进入枚举下一行了,当前行还有没填上的,就直接回溯。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 1e5+10;
int num[8][9],g[8][9];
int res[10][10],vis[10][10],v[30];
int dir[2][2] = {{1,0},{0,1}};
int ans;
void table(){
int cnt = 1;
for(int i=0; i<7; i++)
for(int j=i; j<7; j++)
num[i][j] = num[j][i] = cnt++;
}
bool ok(int x){
for(int i=0; i<8; i++)
if(vis[x][i] == 0) return false;
return true;
}
void dfs(int x,int y,int nu){
if(nu == 28){
ans++;
for(int i=0; i<7; i++){
for(int j=0; j<8; j++)
printf("%4d",res[i][j]);
puts("");
}
puts("");
return ;
}
if(x==7) return ;
if(y==8){
if(!ok(x)) return ; // 这一行没有都被覆盖,这种解不行,回溯
dfs(x+1,0,nu);
return ;
}
if(vis[x][y]){
dfs(x,y+1,nu);
return ;
}
for(int i=0; i<2; i++){
if(i==0 && x==6) continue;
if(i==1 && y==7) continue;
int tx=x+dir[i][0], ty=y+dir[i][1];
int k = num[g[x][y]][g[tx][ty]];
if(vis[tx][ty]) continue;
if(v[k]) continue;
res[x][y] = res[tx][ty] = k;
vis[x][y] = vis[tx][ty] = v[k] = 1;
dfs(x,y+1,nu+1);
vis[x][y] = vis[tx][ty] = v[k] = 0;
}
}
int main(){
table();
int cas=0;
while(~scanf("%d",&g[0][0])){
MS(vis); MS(v); ans=0;
if(cas) printf("\n\n\n");
for(int i=0; i<7; i++)
for(int j=0; j<8; j++){
if(i==0 && j==0) continue;
scanf("%d",&g[i][j]);
}
printf("Layout #%d:\n\n",++cas);
for(int i=0; i<7; i++){
for(int j=0; j<8; j++)
printf("%4d",g[i][j]);
puts("");
}
puts("");
printf("Maps resulting from layout #%d are:\n\n",cas);
dfs(0,0,0);
printf("There are %d solution(s) for layout #%d.\n",ans,cas);
}
return 0;
}