剪邮票 蓝桥杯

12张连在一起的12生肖的邮票。

现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)

比如,下图中,粉红色所示部分就是合格的剪取。

请你计算,一共有多少种不同的剪取方法。

这里写图片描述

题解:

开始想直接dfs,可是会忽略好多种情况,因为dfs的结果是一笔画的,如图二直接dfs就不行。

正确的应该是先dfs 5个点,然后判断这5个点是够连通, 是否仅有1个连通分支

结果:116

方一:利用bfs判断是否连通

#include<stdio.h>
#include<string.h>

typedef struct Nod{//每个方块信息 
    int v;//v为0没取,v为1取了 
    int x;
    int y;
}Node;

int ans,d[4][2]={0,1,1,0,-1,0,0,-1},vis[3][4],sum;
Node n[3][4],Q[13];

int bfs(int a,int b){
    int k=0,top=0,i,j,x,y,x1,y1;
    Q[k++]=n[a][b];//将n[a][b]入队列 
    vis[a][b]=0;
    while(top<k){
        x=Q[top].x;
        y=Q[top].y;
        for(i=0;i<4;i++){//遍历与该点相连且选取了的方块 
          x1=x+d[i][0];
          y1=y+d[i][1];
          if(x1>=0&&x1<=2&&y1>=0&&y1<=3&&vis[x1][y1]==1){
            Q[k++]=n[x1][y1];//入队列 
            vis[x1][y1]=0; 
            sum++;
          }
        }
        top++;//相当于最先进来的出队列 
    }
    return sum;

}

int dfs(int x,int y,int num){
    int i,j,x1,y1;
    if(num==5){
        sum=1;
        for(i=0;i<3;i++){
            for(j=0;j<4;j++){
                vis[i][j]=n[i][j].v;
            }
        }       
        if(bfs(x,y)==5){//如果5个方块连通,加1 
            ans++;
        }
        return 0;
    }
    x1=x;
    y1=y+1;
    if(y1==4){
        x1=x+1;
        y1=0;
    }
    if(x1==3) return 0;

    n[x1][y1].v=1;//该点取 
    dfs(x1,y1,num+1);

    n[x1][y1].v=0;//该点不取 
    dfs(x1,y1,num);
}


int main(){
    int i,j;
    memset(vis,0,sizeof(vis));
    for(i=0;i<3;i++){
        for(j=0;j<4;j++){
            n[i][j].v=0;
            n[i][j].x=i;
            n[i][j].y=j;
        }
    }
    dfs(0,-1,0);
    printf("%d",ans);
}

方二:找一共有几个连通分支,只有一个则正确

#include<stdio.h>
#include<string.h>

int vis[3][4],b[3][4],ans=0,d[4][2]={0,1,1,0,-1,0,0,-1};

int bfs(int x,int y){//类似bfs,找与该点相连通的点 
    int i,j,x1,y1;
    b[x][y]=0;
    for(i=0;i<4;i++){
        x1=x+d[i][0];
        y1=y+d[i][1];
        if(x1>=0&&x1<=2&&y1>=0&&y1<=3&&b[x1][y1]==1){
            bfs(x1,y1);//一直找下去,直到找完 
        }
    }   
}

int dfs(int x,int y,int sum){   
    int i,j,x1,y1;
    if(sum==5){
        for(i=0;i<3;i++){
            for(j=0;j<4;j++){
                b[i][j]=vis[i][j];
            }
        }
        int cnt=0;// 记录有几个连通分支
        for(i=0;i<3;i++){
           for(j=0;j<4;j++){
              if(b[i][j]==1){
                bfs(i,j);
                cnt++;
              }
           }
        }
        if(cnt==1){//只有一个连通分支,5个点是连着的 
            ans++;  
        }   
        return 0;
    }
    x1=x;y1=y+1;
    if(y1==4){
        x1=x+1;
        y1=0;
    }
    if(x1==3) return 0;
    vis[x1][y1]=1;//该点取 
    dfs(x1,y1,sum+1);

    vis[x1][y1]=0;//该点不取 
    dfs(x1,y1,sum);         
}

int main(){
    memset(vis,0,sizeof(vis));
    dfs(0,-1,0);
    printf("%d",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值