解DFS题有感

题目来源:蓝桥杯真题题号118,名字为机器人塔。

链接:

https://www.lanqiao.cn/problems/118/learning/?page=1&first_category_id=1&tag_relation=intersection&tags=DFS&difficulty=20

最后过关的代码:

#include <stdio.h>
#include <stdlib.h>
char arr[500][500]={'\0'};
int ans = 0;
int m,n;
int Check(int f){
    for (int j = 0; j <= f; j++){
      if(arr[f - 1][j] == 'a'){
        if(arr[f][j] != arr[f][j + 1]){
          return 0;
        }
      }
      if(arr[f - 1][j] == 'b'){
        if(arr[f][j] == arr[f][j + 1]){
          return 0;
        }
      }
    }
  return 1;
}
void DFS(int M,int N, int count,int f){
  if(M == 0 && N == 0){
    if(Check(f)){
      ans++;
      return;
    }
  }
  if(f > 0 && count == (f + 1)){
    if(!Check(f)){
      return;
    }
  }
  if(count == (f + 1) ){
    DFS(M,N,0,f+1);
  }
  else{
    if(M > 0){
      arr[f][count] = 'a';
      DFS(M-1,N,count+1,f);
    }
    if(N > 0){
      arr[f][count] = 'b';
      DFS(M,N-1,count+1,f);
    }
  }
  
}
int main(int argc, char *argv[])
{
  scanf("%d %d",&m,&n);
  DFS(m,n,0,0);
  printf("%d",ans);
  return 0;
}

过关前的一次测试:

#include <stdio.h>
#include <stdlib.h>
char arr[30][30]={'\0'};
int ans = 0;
int m,n;
int Check(int f){
  for (int i = 0; i < f; i++){
    for (int j = 0; j <= i; j++){
      if(arr[i][j] == 'a'){
        if(arr[i + 1][j] != arr[i + 1][j + 1]){
          return 0;
        }
      }
      if(arr[i][j] == 'b'){
        if(arr[i + 1][j] == arr[i + 1][j + 1]){
          return 0;
        }
      }
    }
  }
  return 1;
}
void DFS(int M,int N, int count,int f){
  if(M == 0 && N == 0){
    if(Check(f)){
      ans++;
    }
    return;
  }
  if(count == (f + 1) ){
    DFS(M,N,0,f+1);
  }
  else{
    if(M > 0){
      arr[f][count] = 'a';
      DFS(M-1,N,count+1,f);
    }
    if(N > 0){
      arr[f][count] = 'b';
      DFS(M,N-1,count+1,f);
    }
  }
  
}
int main(int argc, char *argv[])
{
  scanf("%d %d",&m,&n);
  DFS(m,n,0,0);
  printf("%d",ans);
  return 0;
}

优化部分

优化的部分是在深搜过程中check函数由最后M与N次数用完后从第一行到最后一行的检查,到每一行输入后以当前行和上一行进行错误检查。第一段代码可以在输入的过程中淘汰掉排列非法的组合,相对第二段减少了运行时间。

原①

int Check(int f){
  for (int i = 0; i < f; i++){
    for (int j = 0; j <= i; j++){
      if(arr[i][j] == 'a'){
        if(arr[i + 1][j] != arr[i + 1][j + 1]){
          return 0;
        }
      }
      if(arr[i][j] == 'b'){
        if(arr[i + 1][j] == arr[i + 1][j + 1]){
          return 0;
        }
      }
    }
  }
  return 1;
}

优化后①

int Check(int f){
    for (int j = 0; j <= f; j++){
      if(arr[f - 1][j] == 'a'){
        if(arr[f][j] != arr[f][j + 1]){
          return 0;
        }
      }
      if(arr[f - 1][j] == 'b'){
        if(arr[f][j] == arr[f][j + 1]){
          return 0;
        }
      }
    }
  return 1;
}

原②

if(M == 0 && N == 0){
    if(Check(f)){
      ans++;
    }
    return;
  }

优化后②

if(M == 0 && N == 0){
    if(Check(f)){
      ans++;
      return;
    }
  }
  if(f > 0 && count == (f + 1)){
    if(!Check(f)){
      return;
    }
  }

明显的变化在于从双层从头开始的循环到每次每行输入完之后的检测,时间复杂度明显减小。

PS

新手写的,代码或排版写的不好,大佬可以提提意见^_^)>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值