题目链接
题面
如下图, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)。
求多少种剪法。
思路
间接相当于求路径/条数/方法数等,所以我们可以很容易的想到利用 DFS 来做。
但是我没有考虑到的是,该题的图三(下图):
这种走法(T型呀、Π型呀等),DFS是走不到的,DFS最直观的就是一条路走到头,所以可以说,DFS不会拐弯,所以题目给定的第三幅图其实直接用一般的DFS模板我
们解出来会比正确答案少,好像解出来是八十几来着,但是正确的答案是116。
所以这题就是DFS变形,因为得另外开一个数组去记录路径,网上有好多方法,我参考的是直接通过二进制位移,就是每次DFS的时候如果发现满足条件5的就把整个图都遍历一下,把book为真的直接 x<<=1 就行(这里优先级<<大!?)
PS:蓝桥杯都变形了吗……
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
int a[5][5],ans;
bool book[5][5],book1[100010];
int to[4][2]= {{-1,0},{0,1},{1,0},{0,-1}};
void dfs(int cnt)
{
if(cnt==5) // 不要急着return,对这条路径进行处理(记录)
{
int w=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=4; j++)
{
w+=book[i][j];
w<<=1; //不加()?
}
}
if(!book1[w])
{
ans++;
book1[w]=1;
// return;
}
return;
}
// for(int i=0; i<4; i++) //不知道直接 *k是否可以?
// {
// for
// } //这里写的不是遍历方向,方向放在两个for里面写
for(int i=1; i<=3; i++)
{
for(int j=1; j<=4; j++)
{
if(book[i][j]) // *** don't forget 不是==0
{
for(int k=0; k<4; k++)
{
int tx=i+to[k][0];
int ty=j+to[k][1]; // 这里用xy,因为1没有传入xy,2该图直接用对应坐标即可
if(tx>=1&&tx<=3&&ty>=1&&ty<=4&&!book[tx][ty])
{
book[tx][ty]=1;
dfs(cnt+1);
book[tx][ty]=0;
}
}
}
}
}
}
int main()
{
ans=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=4; j++)
{
book[i][j]=1;
dfs(1); // 表示长度为5中长度为1的已经搜到了
book[i][j]=0; //因为是搜索路径,所以DFS需要标记+取消标记
}
}
cout<<ans<<endl;
return 0;
}
我的DFS失败代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
int a[5][5],cnt,ans;
bool book[5][5];
int to[4][2]= {{-1,0},{0,1},{1,0},{0,-1}};
void dfs(int x,int y,int ss)
{
if(ss>=5) return ;
for(int i=0; i<4; i++)
{
for(int k=0; k<=4; k++)
{
int tx=x+to[i][0]*k;
int ty=y+to[i][1]*k;
if(tx>=1&&tx<=3&&ty>=1&&ty<=4&&!book[tx][ty])
{
book[tx][ty]=1;
dfs(tx,ty,ss+1);
book[tx][ty]=0;
}
}
}
}
int main()
{
cnt=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=4; j++)
a[i][j]=++cnt;
}
for(int i=1; i<=3; i++)
{
for(int j=1; j<=4; j++)
{
memset(book,0,sizeof(book));
ans++;
dfs(i,j,0);
}
}
cout<<ans<<endl;
return 0;
}