剪邮票
如图
,
有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如
中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路: 直接使用DFS是搜不到第二种图的情况的,所以这时候应该改变策略。
使用深搜从12个数里面取5个数,然后把这5个数的转换成对应的坐标,在用第二个DFS判断这5个点是否连通即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <set>
using namespace std;
const int n = 5;
int a[15];
int vis[15];
int check[15][15];
int ans = 0;
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
int n2;
void dfs2(int x,int y)
{
for(int i=0;i<4;i++)
{
int xx = x+dir[i][0];
int yy = y+dir[i][1];
if(xx>=1 && xx<=3 && yy>=1 && yy<=4 && check[xx][yy])
{
check[xx][yy] = 0;
n2++;
dfs2(xx,yy);
}
}
}
void dfs(int num,int no)
{
if(num == n)//num
{
memset(check,0,sizeof(check));
int x,y;
for(int i=0;i<5;i++)
{
y = a[i]%4;
if(y == 0)
{
y=4;
x = a[i]/4;
}
else
{
x = a[i]/4+1;
y = a[i]%4;
}
check[x][y] = 1;
}
check[x][y] = 0;
n2 = 1;
dfs2(x,y);
if(n2 == 5)
ans++;
}
for(int i=no;i<=12;i++)//从12个数里面选五个,并且从小到大排列
{
if(!vis[i])
{
vis[i] = 1;
a[num] = i;
dfs(num+1,i);//这里第二个参数很重要,填i是组合,填no是排列
vis[i] = 0;
}
}
}
int main()
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
dfs(0,1);
cout<<ans<<endl;
return 0;
}
PS:不断地被超霸鞭笞啊,自己是真的弱,太弱了,蒟蒻,有好多东西都还得加强啊,不要太死板去记代码了,应该理解原理啊!!