题目大意:
题目链接:https://www.luogu.org/problem/P4205
智慧珠游戏拼盘由一个三角形盘件和 12 个形态各异的零件组成。拼盘的盘 件如图 1 所示
可以放到盘件的任一位置,条件是能有地方放,且 尺寸合适,所有的零件都允许旋转(0º、90º、180º、270º)和翻转(水平、竖直)。
现给出一个盘件的初始布局,求一种可行的智慧珠摆放方案,使所有的零件 都能放进盘件中。
思路:
把每一块智慧珠的所有摆放方式打出来,然后暴搜依次确定位置。
还有什么好说的吗
注意不用手动把所有的情况打出来,只要打出其中一个,让程序自己将这个图形旋转、翻转然后打印进去。注意一个图形是否翻转,以及每次旋转的角度是要打进去的。这样可以将行的暴搜压缩成行。
先把难填的图形填进去,方便剪枝。
剪枝就是每到一个局面就泳并查集判断每一个没放智慧珠的空联通快的大小,如果小于3,或者大小是6,就直接返回即可。
最后卡一个搜索次数,达到就直接退了。
时间复杂度玄学
代码:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int tot,flag,pos[13][10][10][3],map[4][4],cpy[4][4],cnt[13],sum[13],vis[15][15],father[200],size[200];
bool used[13];
double T;
char ch;
const int Map[13][4][4]=
{
{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,0,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,1,1,0},{0,0,0,0}},
{{1,1,1,1},{0,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,0},{1,0,1,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,0},{0,0,1,1},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,1,0},{0,1,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{0,1,1,0},{0,0,0,0}},
{{1,1,1,1},{1,0,0,0},{0,0,0,0},{0,0,0,0}}
};
const int Swap[13]={0,0,0,1,0,0,1,0,1,1,0,0,1};
const int Rotate[13]={0,15,3,15,1,15,15,15,15,15,1,15,15};
const int dx[]={0,0,0,-1,1},dy[]={0,-1,1,0,0};
const int next[]={0,2,4,1,-1,3,12,6,5,11,9,7,8};
inline void add(int S)
{
for (register int k=1;k<=4;k++)
{
for (register int i=0;i<4;i++)
for (register int j=0;j<4;j++)
cpy[i][j]=map[3-j][i];
memcpy(map,cpy,sizeof(map));
if (Rotate[S]&(1<<k-1))
{
int px=-1,py,q=0;
cnt[S]++;
for (register int i=0;i<4;i++)
for (register int j=0;j<4;j++)
if (map[i][j])
{
if (px<0) px=i,py=j;
else
{
q++;
pos[S][cnt[S]][q][1]=i-px;
pos[S][cnt[S]][q][2]=j-py;
}
}
}
}
if (!Swap[S]) return;
for (register int i=0;i<4;i++)
for (register int j=0;j<2;j++)
swap(map[i][j],map[i][3-j]);
for (register int k=1;k<=4;k++)
{
for (register int i=0;i<4;i++)
for (register int j=0;j<4;j++)
cpy[i][j]=map[3-j][i];
memcpy(map,cpy,sizeof(map));
if (Rotate[S]&(1<<k-1))
{
int px=-1,py,q=0;
cnt[S]++;
for (register int i=0;i<4;i++)
for (register int j=0;j<4;j++)
if (map[i][j])
{
if (px<0) px=i,py=j;
else
{
q++;
pos[S][cnt[S]][q][1]=i-px;
pos[S][cnt[S]][q][2]=j-py;
}
}
}
}
}
inline void prepare()
{
for (register int i=1;i<=12;i++)
{
memcpy(map,Map[i],sizeof(map));
for (register int j=0;j<4;j++)
for (register int k=0;k<4;k++)
sum[i]+=Map[i][j][k];
add(i);
}
}
inline bool check(int x,int y,int S,int k)
{
for (register int i=1;i<=sum[S];i++)
{
int xx=x+pos[S][k][i][1],yy=y+pos[S][k][i][2];
if (vis[xx][yy] || xx>10 || yy>xx || xx<1 || yy<1) return 0;
}
return 1;
}
inline int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
inline int com(int x,int y)
{
return (x-1)*10+y;
}
inline void dfs(int x)
{
if (x==-1)
{
flag=1;
return;
}
tot++;
for (register int i=1;i<=10;i++)
for (register int j=1;j<=i;j++)
{
father[com(i,j)]=com(i,j);
size[com(i,j)]=1;
}
for (register int i=1;i<=10;i++)
for (register int j=1;j<=i;j++)
if (!vis[i][j])
for (register int k=1;k<=4;k++)
{
int xx=i+dx[k],yy=j+dy[k];
if (!vis[xx][yy])
{
if (xx<1 || xx>10 || yy<1 || yy>xx) continue;
int p=find(com(i,j)),q=find(com(xx,yy));
if (p==q) continue;
size[p]+=size[q]; father[q]=p;
}
}
for (register int i=1;i<=10;i++)
for (register int j=1;j<=i;j++)
if (!vis[i][j] && size[find(com(i,j))]<3 || size[find(com(i,j))]==6)
return;
if (used[x])
{
dfs(next[x]);
return;
}
for (register int i=1;i<=10;i++)
for (register int j=1;j<=i;j++)
for (int k=1;k<=cnt[x];k++)
if (check(i,j,x,k))
{
for (register int l=1;l<=sum[x];l++)
vis[i+pos[x][k][l][1]][j+pos[x][k][l][2]]=x;
dfs(next[x]);
if (tot>=800000) return;
if (flag) return;
for (register int l=1;l<=sum[x];l++)
vis[i+pos[x][k][l][1]][j+pos[x][k][l][2]]=0;
}
}
int main()
{
prepare();
for (register int i=1;i<=10;i++)
for (register int j=1;j<=i;j++)
{
while (ch=getchar()) if (ch=='.' || (ch>='A' && ch<='Z')) break;
if (ch!='.')
{
used[ch-'A'+1]=1;
vis[i][j]=ch-'A'+1;
}
}
dfs(10);
if (flag==1)
for (register int i=1;i<=10;i++,putchar(10))
for (register int j=1;j<=i;j++)
printf("%c",vis[i][j]+'A'-1);
else printf("No solution
");
return 0;
}