标题:方格分割
6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。
如图:p1.png, p2.png, p3.png 就是可行的分割法。
试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。
请提交该整数,不要填写任何多余的内容或说明文字。
由于图像是中心对称,所以我们穷举左边的18个方格,共有2^18=262144种可能的情况,穷举出左边,通过对称再得到右边18个方格的情况,从而得到整附图:
for(int i=0;i < (1<<18);++i) //i=0~2^18-1
{
for(int l=0;l<6;l++)
{
for(int c=0;c < 3;c++)
{
if(i&(1<<cnt)) //把i的每一位取出填入图形
{
mp[l][c] = 1; //填充左半部分 1代表橘色 0代表黄色
mp[5-l][5-c] = 0; //对称得到右半部分
}else
{
mp[l][c] = 0;
mp[5-l][5-c] = 1;
}
}
}
然后对填充后的图形进行连通性检测,如果填充后的图形存在18个方块的连通域则符合要求,方案数加一,用DFS检测连通:
int vis[6][6];
int dx[8]={1, 0, 0,-1};
int dy[8]={0,-1, 1, 0};
int node_cnt;
int dfs(int x, int y)
{
for(int i=0;i < 4;i++) //从当前方格的上,下,左,右进行搜索
{
int nx = x + dx[i];
int ny = y + dy[i];
if(node_cnt==18) return node_cnt; //已找到18个连通的方块,则进行剪枝
if(0<=nx && nx < 6 && 0<=ny && ny <6)
{
if(mp[nx][ny]==mp[x][y]&&vis[nx][ny]==0) //找到同一区域方块
{
vis[nx][ny]=1; //,标记
node_cnt++; //方块数加1
dfs(nx,ny);
}
}
}
return node_cnt;
}
以下是完整代码:
#include <iostream>
#include <cstring>
using namespace std;
int mp[6][6];
int vis[6][6];
int dx[8]={1, 0, 0,-1};
int dy[8]={0,-1, 1, 0};
int node_cnt;
void printmp()
{
for(int i=0; i < 6;i++)
{
for(int j=0 ;j < 6;j++)
{
cout<<mp[i][j]<<" ";
}
cout<<endl;
}
}
int dfs(int x, int y)
{
for(int i=0;i < 4;i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if(node_cnt==18) return node_cnt;
if(0<=nx && nx < 6 && 0<=ny && ny <6)
{
if(mp[nx][ny]==mp[x][y]&&vis[nx][ny]==0)
{
vis[nx][ny]=1;
node_cnt++;
dfs(nx,ny);
}
}
}
return node_cnt;
}
int main()
{
int ans=0;
for(int i=0;i < (1<<18);++i)
{
int cnt=0;
for(int l=0;l<6;l++)
{
for(int c=0;c < 3;c++)
{
if(i&(1<<cnt))
{
mp[l][c] = 1;
mp[5-l][5-c] = 0;
}else
{
mp[l][c] = 0;
mp[5-l][5-c] = 1;
}
cnt++;
}
}
memset(vis,0,sizeof(vis));
node_cnt = 1;
vis[0][0] = 1;
if(dfs(0,0)==18) ans++;
// printmp();
// cin>>cnt;
}
cout<<ans/4; //中心对称算一种,最后还要除以4
return 0;
}
最终答案为:509