题目
有12张连在一起的12生肖的邮票。从中剪下5张,要求邮票连通(角对角不满足要求),求方案数目。
解题思路
递归得到12选5的组合数,将5个数标注并挨个沿着它四周递归,如果5个数是连在一起的,一次递归就能全部标注,如果能一次标注成功则为真,数目加一。
代码
方法一:
#include<stdio.h>
#include<string.h>
int vis[3][4],b[3][4];
int ans=0;
int dfs(int i,int j){
b[i][j] = -1;
if(i-1>=0&&b[i-1][j]==1) dfs(i-1,j);
if(i+1<=2&&b[i+1][j]==1) dfs(i+1,j);
if(j-1>=0&&b[i][j-1]==1) dfs(i,j-1);
if(j+1<=3&&b[i][j+1]==1) dfs(i,j+1);
}
bool check(){
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
b[i][j]=vis[i][j];
}
}
int cnt=0; // 记录有几个连通分支
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(b[i][j]==1){
dfs(i,j);
cnt++;
}
}
}
return cnt==1;
}
void f(int x,int y,int sum){
int x1,y1;
if(sum==5){
if(check()){
ans++;
return;
}
}
x1=x;y1=y+1;
if(y1==4){
x1=x+1;
y1=0;
}
if(x1==3)
return;
vis[x1][y1]=1;//该点取
f(x1,y1,sum+1);
vis[x1][y1]=0;//该点不取
f(x1,y1,sum);
}
int main(){
memset(vis,0,sizeof(vis));
f(0,-1,0);
printf("%d",ans);
}
注意点:
- f函数的列参数为-1,因为f函数是先加一的
- if(num==1)需要放在if(x1==3)前面,因为这两个都有return,当if(x1==3)放前面时,种数会少一些,因为没等到if(num==1)时,已经结束了
- 这vis的下标要用x1,y1而不是x,y。因为f是(0,-1)开始的,x1,y1才是当前表格的参数