纯小白蓝桥杯备赛笔记--DAY2(深度优先搜索)

  1. 真题--分考场

  • 暴力dfs求最优解+剪枝(纯C)

  • #include<stdio.h>
    #include<string.h>
    #define N 301
    #define min(a,b) a>b?b:a //返回较小的这个数
    int gxb[N][N];//关系表 
    int p[N][N];// 房间状态  
    int num=N,n;
    void DFS(int x,int kcs){//x 代表当前安排了多少个人 kcs 代表考场数
      if(kcs>=num)return;//剪子 
      if(x==n+1){num=min(num,kcs);return;}//如果已经安排了n个人,进行判断  
       int j,k;
      for(j=1;j<=kcs;j++){//枚举考场
         k=0;
         while(p[j][k]&&!gxb[x][p[j][k]])k++;//找到一个空位 并且与该考场人无关系 
      if(p[j][k]==0)p[j][k]=x,DFS(x+1,kcs),p[j][k]=0;//满足条件 进行下一考生 
       }                                    //回溯 
       p[j][0]=x;
       DFS(x+1,kcs+1);// 如果所有房间都不满足条件 增加房间 
       p[j][0]=0;//回溯 
    }
    int main(){
      int m,i,s1,s2;
      memset(gxb,0,sizeof(gxb));
      memset(p,0,sizeof(p));
      scanf("%d\n%d",&n,&m);
      for(i=1;i<=m;i++){ 
       scanf("%d%d",&s1,&s2);
       gxb[s1][s2]=gxb[s2][s1]=1;//建关系 
      }
        DFS(1,1);
      printf("%d\n",num);
      return 0;
    }
    

  • 详解代码:

memset函数:

  • memset(要操作的数组名,要设置的值,要操作的字节数)

  • 对于char类型的数组来说,一个字符占据一个字节。

  • 对于int类型的数组来说,一个数字代表四个字节,也就是4*8位二进制位。

  • 举例:

    int a[4];
    memset(a,1,sizeof(a);
    //注释
    先看输出结果:16843009 16843009 16843009 16843009
    对于第一个元素a[0]来说:就是把1(00000001)分别赋值给四个字节
    a[0]=00000001 00000001 00000001 00000001;
    也就是十进制的16843009

深度优先搜索:

  • 对于递归的理解:符合条件的输出之后,由最后一个值开始向前走。

#include<stdio.h>
 //创建dfs函数
 void dfs(int n){
         printf("n1=%d\n",n);
         //回归
         if(n>=10)
         return;
         //递进
         dfs(n+1); 
         printf("n2=%d\n",n);
 } 
int main()
{
        dfs(0);
        return 0;
 }
  • 用递归求数组的最大值和最小值以及和。

#include<stdio.h>
int arr[100];
int n;
int maxa=0;
int mina=9999;
long long sum=0;
int max(int x,int y)
{
        if(x>y)
        return x;
        else
        return y;
}
int min(int x,int y)
{
        if(x<y)
        return x;
        else
        return y;
}
//求最大值 
void dfs1(int x)
{
        if(x>=n)
        return;
        else
        maxa=max(maxa,arr[x]);
        dfs1(x+1);        
}
//求最小值
void dfs2(int x)
{
        if(x>=n)
        return;
        else
        mina=min(mina,arr[x]);
 } 
 //求和
 void dfs3(int x)
 {
         if(x>=n)
         return;
         else
         sum=sum+arr[x];
         dfs3(x+1);
  } 
int main()a
{
        scanf("%d",&n);
        for(int i=0;i<n;i++){
                scanf("%d",&arr[i]);
        } 
        dfs1(0);//求最大值
         printf("%d\n",maxa);
         dfs2(0);
         printf("%d\n",mina);
         dfs3(0);
         printf("%d\n",sum);
        return 0;
 }

要注意的是:c语言没有内置max和min函数,需要额外定义。

  • 二维数组的遍历:(运行起来比较直观,遇到尽头会返回)

#include<stdio.h>
int arr[10][10];
bool b[10][10];
//判断上述数组中的元素有没有被遍历过 
void dfs(int x,int y)
{
        if(x>5 or y>5)
        return;
        for(int i=0;i<5;i++)
        {
                for(int j=0;j<5;j++)
                {
                        printf("%d",arr[i][j]);
                }
                printf("\n");
        }
        printf("\n");
        if(arr[x][y]==0)
        {
        arr[x][y]=1;
        dfs(x+1,y); //竖直方向的递进 
        dfs(x,y+1); 
        }
 } 
int main()
{
        dfs(0,0);
        return 0;
}
  • 求二维数组的最大值:

  • #include<stdio.h>
    int arr[10][10],maxa=0;
    int n,m;
    bool bj[10][10];//是否被标记过 
    int max(int x,int y)
    {
            if(x>y)
            return x;
            else
            return y;
    }
    void dfs(int a,int b){
            if(a>=n or b>=m)
            return ;
            if(bj[a][b]==false){
                    bj[a][b]=true;
                    maxa=max(maxa,arr[a][b]);
                    dfs(a+1,b);
                    dfs(a,b+1);
            }
    }
    int main()
    {
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++)
                    for(int j=0;j<m;j++)
                    scanf("%d",&arr[i][j]);
            dfs(0,0);
            printf("%d",maxa);
            return 0;
     } 

  • 输出4的全排列

#include<stdio.h>
int ans=0;//有多少种排列 
int arr[5];
bool b[5];
void dfs(int n)
{
        if(n>4)//终止条件 
        {
                ans++;
                for(int i=1;i<=4;i++)
                printf("%d ",arr[i]);
                printf("\n");
        }
        for(int i=1;i<=4;i++)
        {
                if(b[i]==false)
                {
                        arr[n]=i;
                        b[i]=true;
                        dfs(n+1);        
                        b[i]=false;
                }
        }
}
int main()
{
        dfs(1);
        printf("一共有%d种排列",ans);
        return 0;
}
  • 四阶数独

 
#include<stdio.h>
int ans;
int arr[25];
bool b1[5][5];//行 
bool b2[5][5];//列 
bool b3[5][5];//块
int hang[17]={0,1,1,1,1,
                                2,2,2,2,
                                3,3,3,3,
                                4,4,4,4};
int lie[17]={0,1,2,3,4,
1,2,3,4,
1,2,3,4,
1,2,3,4};
int kuai[17]={0,1,1,2,2,
1,1,2,2,
3,3,4,4,
3,3,4,4};
void dfs(int x)
{
        //回归
        if(x>16)
        {
                ans++;
                for(int i=1;i<=16;i++){
                        printf("%d ",arr[i]);
                        if(i%4==0)
                        printf("\n");
                }
                        printf("\n");
                        return ;
        }
        //递进 
        int h=hang[x],l=lie[x],k=kuai[x];
        for(int i=1;i<=4;i++)
        {
                if(b1[h][i]==false and b2[l][i]==false and b3[k][i]==false){
                        arr[x]=i;
                        b1[h][i]==true;b2[l][i]==true; b3[k][i]==true;
                        dfs(x+1);
                        b1[h][i]==false;b2[l][i]==false; b3[k][i]==false;
                }
        }
}
int main()
{
        dfs(1);
        printf("%d",ans);
        return 0;
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值