代码如下。题目大意是给定连通块大小n,输入平面大小h,w,要求在这样大小的平面内大小为n的连通块有多少种,其中经过平移,旋转,对称的同一连通块视为一种
我的思路是在这个平面内从左上角开始搜索,对于每个没有放置的格子,分别搜索是否放置,如果搜到了答案,则用change函数将该答案所有可能的变化存起来,之后搜到答案后进行判重,dfs里的后四个参数分别记录的是此时搜到的连通块的边界情况
现在的问题是我的程序得到的答案有些出入。。请问我的思路有问题吗(暂不考虑时间复杂度),如果没有,为什么结果错误?
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10;
int n,w,h;
int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
int ans;
bool vis[MAXN + 5][MAXN + 5],shape[40000][MAXN + 5][MAXN + 5];
int num;
bool check(int x,int y){
for(int i = 0; i < 4; i++){
int tx = x + dx[i];
int ty = y + dy[i];
if(x >= 1 && x <= w && y >= 1 && y <= h && tx >= 1 && ty <= h && tx <= w && ty >= 1 && vis[tx][ty])return 1;
}
return 0;
}
void out(){
for(int i = 1; i <= w; i++){
for(int j = 1; j <= h; j++){
cout << vis[i][j];
}
puts("");
}
puts("");
}
bool is_(int le,int ri,int hi,int lo){
bool flag,flag1 = 1;
for(int i = 1; i <= num; i++){
flag = 0;
for(int j = 1; j <= lo; j++){
for(int k = 1; k <= ri; k++){
if(vis[j + hi - 1][k + le - 1] != shape[i][j][k]){
flag = 1;
break;
}
}
if(flag)break;
}
if(!flag){
flag1 = 0;
return 0;
}
}
return 1;
}
void change(int le,int ri,int hi,int lo){
for(int i = hi; i <= lo; i++){
for(int j = le; j <= ri; j++){
shape[num + 1][i - hi + 1][j - le + 1] = vis[i][j];//原本形态
shape[num + 2][i - hi + 1][j - le + 1] = vis[i][ri - j + 1];//原本形态左右翻转翻转
}
}
num += 2;
for(int i = hi; i <= lo; i++){
for(int j = le; j <= ri; j++){
shape[num + 1][lo - i + 1][j - le + 1] = vis[i][j];//上下翻转
shape[num + 2][lo - i + 1][j - le + 1] = vis[i][ri - j + 1];//上下翻转后再左右翻转
}
}
num += 2;
if((ri - le + 1) <= n && (lo - hi + 1) <= n){
for(int i = ri; i >= le; i--){
for(int j = hi; j <= lo; j++){
shape[num + 1][ri - i + 1][j - hi + 1] = vis[j][i];//逆时针旋转九十度
shape[num + 2][ri - i + 1][j - hi + 1] = vis[lo - j + 1][i];//逆时针旋转九十度后再左右对称
}
}
num += 2;
for(int i = le; i <= ri; i++){
for(int j = hi; j <= lo; j++){
shape[num + 1][i - le + 1][j - hi + 1] = vis[j][i];//逆时针旋转九十度后上下翻转
shape[num + 2][i - le + 1][j - hi + 1] = vis[lo - j + 1][i];//左右翻转
}
}
num += 2;
}
}
void dfs(int x,int y,int cnt,int le,int ri,int hi,int lo){//坐标,连通块大小,最左,最右,最上,最下
if(cnt >= n){
if(is_(le,ri,hi,lo) && cnt == n){
out();
ans++;
change(le,ri,hi,lo);
}
return;
}
if(x > w || y > h)return;
if((check(x,y) && cnt < n) || cnt == 0){
vis[x][y] = 1;
if(y > 1 && !vis[x][y - 1] && cnt + 2 <= n){//十字情况
vis[x][y - 1] = 1;
if(y + 1 <= h)dfs(x,y + 1,cnt + 2,min(le,y - 1),max(ri,y),min(hi,x),max(lo,x));//是否到边缘
else dfs(x + 1,1,cnt + 2,min(le,y - 1),max(ri,y),min(hi,x),max(lo,x));
vis[x][y - 1] = 0;//回溯
}
if(y + 1 <= h)dfs(x,y + 1,cnt + 1,min(le,y),max(ri,y),min(hi,x),max(lo,x));
else dfs(x + 1,1,cnt + 1,min(le,y),max(ri,y),min(hi,x),max(lo,x));
vis[x][y] = 0;
}
vis[x][y] = 0;
if(y + 1 <= h){
dfs(x,y + 1,cnt,le,ri,hi,lo);
}
else dfs(x + 1,1,cnt,le,ri,hi,lo);
return;
}
int main(){
cin >> n >> h >> w;
dfs(1,1,0,99,0,99,0);//左上角开始,对于每一个格子,判一下是否放一个灰块
change(1,4,1,5);
cout << ans << endl;
}
</details>
你的程序和思路看起来都是正确的。这个程序是寻找所有可能的连通块,并通过一系列变换(旋转、翻转等)去除重复的结果。你的dfs
函数能够确保搜索到所有可能的连通块,而change
函数能够把每一个连通块所有可能的变化存起来。同时,你的is_
函数可以正确判断一个新的形状是否已经存在。
然而,我觉得可能出现错误的原因是在is_
函数中,你只对当前形状进行了一次匹配,如果它在数据库中没有直接的匹配,你就将其视为新的形状。但是,我们知道一个形状可能经过旋转或翻转后与数据库中的形状相匹配。所以,我建议你在is_
函数中增加对形状所有可能变换的检查。
另外,你在dfs
函数中多次使用了固定值 99
作为参数,这可能会导致某些边界条件的错误。应该使用变量代替这些固定值,或者在注释中说明为什么使用这些特定的值。
最后,我建议你添加更多的注释来解释代码的工作原理,这对于理解你的代码非常有帮助。