19694 五子棋对弈

 理解:棋盘上先写满0,然后枚举的时候就像离散数学里面按照从二进制从大到小写真值表那样

如:

 2.在调用递归的时候,dfs(24)是最后一个位置(5*5)棋盘,则还会调用dfs(25),这里dfs(25)的作用:在棋盘满的时候返回


#include<iostream>
using namespace std;

int mp[5][5]; // 定义一个5x5的矩阵,用于存储0和1
long long sum=0; // 用于统计满足条件的排列数量

// 检查函数,用于验证当前矩阵是否满足条件
void check(){
    int a=0; // 用于统计矩阵中1的个数
    for(int i=0;i<5;i++){
        for(int j=0;j<5;j++){
            if(mp[i][j]==1) a++; // 统计1的数量
        }
    }
    if(a!=13) return; // 如果1的个数不是13,不满足条件,直接返回

    // 检查主对角线和副对角线的和是否为5的倍数
    int count=0;
    count += mp[0][0] + mp[1][1] + mp[2][2] + mp[3][3] + mp[4][4]; // 主对角线和
    if(count % 5 == 0) return; // 如果主对角线和为5的倍数,不满足条件
    count = 0; // 重置count

    count += mp[0][4] + mp[1][3] + mp[2][2] + mp[3][1] + mp[4][0]; // 副对角线和
    if(count % 5 == 0) return; // 如果副对角线和为5的倍数,不满足条件
    count = 0; // 重置count

    // 检查每一行和每一列的和是否为5的倍数
    for(int i=0;i<5;i++){
        count = mp[i][0] + mp[i][1] + mp[i][2] + mp[i][3] + mp[i][4]; // 行和
        if(count % 5 == 0) return; // 如果行和为5的倍数,不满足条件
        count = 0; // 重置count

        count = mp[0][i] + mp[1][i] + mp[2][i] + mp[3][i] + mp[4][i]; // 列和
        if(count % 5 == 0) return; // 如果列和为5的倍数,不满足条件
        count = 0; // 重置count
    }

    // 如果所有检查都通过,增加满足条件的排列数量
    sum++;
}

// 深度优先搜索函数,用于生成所有可能的矩阵排列
void dfs(int num){ // num表示当前填充的位置编号
    if(num == 25){ // 如果棋盘已满(5x5棋盘共有25个位置)
        check(); // 检查当前排列是否满足条件
        return;
    }
    int x = num / 5, y = num % 5; // 将位置编号转换为棋盘上的坐标
    mp[x][y] = 0; // 先尝试在当前位置放置0
    dfs(num + 1); // 递归填充下一个位置
    mp[x][y] = 1; // 再尝试在当前位置放置1
    dfs(num + 1); // 递归填充下一个位置
}

int main(){
    dfs(0); // 从位置0开始,遍历所有可能的排列
    cout << sum; // 输出满足条件的排列数量,预期结果为3126376
    return 0;
}

#include<bits/stdc++.h>

using namespace std;

long long ans=0;
int mp[5][5];
void check()
{
	int a=0;
  for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
    {
      if(mp[i][j]==1) a++;
    }
  }
  if(a!=13) return ;
	
  int cnt=0;
  for(int i=0;i<5;i++)
  {
    cnt+=mp[i][i];
  }
  if(cnt%5==0) return ;
  cnt=0;

  for(int i=0;i<5;i++)
  {
    cnt+=mp[i][4-i];
  }
  if(cnt%5==0) return ;
  cnt=0;

  for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
    {
      cnt+=mp[i][j];
    }
    if(cnt%5==0) return ;
     cnt=0;//这个清零放置的位置是特别注意的
    //当计算完成之后判断,若非法则返回,否则清零进行下一次计算
  }
//若将清零放在for循环外面,则不是判断每一行是否合法
 
  for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
    {
      cnt+=mp[j][i];
    }
    if(cnt%5==0) return ;
     cnt=0;
  }
  
  ans++;
}

void dfs(int num)
{
  if(num==25)
  {
    check();
    return ;
  }

  int x=num/5,y=num%5;
  mp[x][y]=1;
  dfs(num+1);
  mp[x][y]=0;
  dfs(num+1);
  
}
int main()
{
  dfs(0);
  cout<<ans;
  return 0;
}

 设置cnt是为了判断,

对每行、每列、对角线进行判断。

但需要需要注意的是,每一行和每一列不同与对角线的是对角线只有一个for循环,在for循环之外添加检查。

但是每行(列)有两层循环,需要在第一层循环设检查,这个要注意逻辑。不能设置在外面。

#include<bits/stdc++.h>

using namespace std;
long long ans=0;
int mp[5][5]={};

void check()
{
  int a=0;
  for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
      if(mp[i][j]==1) a++;
  }

  if(a!=13) return ;

  int cnt=0;
  for(int i=0;i<5;i++)
  {
    cnt+=mp[i][i];
  }
  if(cnt%5==0) return ;
  cnt=0;

  for(int i=0;i<5;i++)
  {
    cnt+=mp[i][4-i];
  }
  if(cnt%5==0) return ;
  cnt=0;

   for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
      cnt+=mp[j][i];

    if(cnt%5==0) return ;
    cnt=0;
  }
 ;

  for(int i=0;i<5;i++)
  {
    for(int j=0;j<5;j++)
      cnt+=mp[i][j];

      if(cnt%5==0) return ;
      cnt=0;
  }


  ans++;
}

void dfs(int num)
{
  if(num==25)
  {
    check();
    return ;//??
  }
  int x=num/5,y=num%5;
  mp[x][y]=1;
  dfs(num+1);
  mp[x][y]=0;
  dfs(num+1);
}

int main()
{
  dfs(0);
  cout<<ans;
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值