华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
楼主: admin
打印 上一主题 下一主题

202003 pmn的变形使用讲课

[复制链接]

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
11#
 楼主| 发表于 2020-3-21 19:56:14 | 只看该作者
1*2 的骨牌去覆盖2*2的格子有两种情况:
1 1
2 2

1 2
1 2
其实就是骨牌横着摆和竖着摆两种,1*2覆盖4*4的格子呢,有36种情况:
请你编程显示出来。
可以理解成间隔排列的加强版
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
12#
 楼主| 发表于 2020-3-21 20:03:44 | 只看该作者
首先,显然想的到,枚举横着和竖着两种情况,知道第8块放下去为止
void pr(){ 打印棋盘}
void dfs(int i)
{  if (i>8) pr();
    else
    {
      横排
      竖排
    }
}
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
13#
 楼主| 发表于 2020-3-21 20:05:21 | 只看该作者
棋盘怎么表示,我建议大家用a(0)-a(15)表示16个格子,当然也人想用a(1)(1)到 a(4)(4),等下你就会发现a(0)-a(15)好!
回复 支持 1 反对 0

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
14#
 楼主| 发表于 2020-3-21 20:07:05 | 只看该作者
横着排,那么要求i不在最右一列,a(i)和 a(i+1)都==0
竖着排,那么要求i不在最后一行,a(i)和 a(i+4)都==0
那么其他的求和间隔排列一样了。
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
15#
 楼主| 发表于 2020-3-21 20:20:09 | 只看该作者
程序和间隔拍列有相似,可以对比看看,
  1. #include <iostream>
  2. using namespace std;
  3. int a[20],k=0,ans;
  4. void pr()  ///很有水平
  5. {
  6.         cout<<endl<<++ans;
  7.         for (int i=0; i<=15; i++)
  8.         {
  9.                 if (i%4==0) cout<<endl;
  10.                 cout<<a[i]<<' ';
  11.         }
  12. }
  13. void  dfs(int i)
  14. {
  15.         if (i>15) pr();
  16.         else  if (a[i]>0)  dfs(i+1);
  17.         else
  18.         {
  19.                 ///heng
  20.                 if ( (i%4<3) && a[i+1]==0)
  21.                 {
  22.                         k++;
  23.                         a[i]=a[i+1]=k; ///放
  24.                         dfs(i+2);
  25.                         a[i]=a[i+1]=0; ///还回来 同间隔排列
  26.                         k--;
  27.                 }
  28.                 ///shu
  29.                 if ((i/4<3) && a[i+4]==0)
  30.                 {
  31.                         k++;
  32.                         a[i]=a[i+4]=k; ///放
  33.                         dfs(i+1);
  34.                         a[i]=a[i+4]=0; ///还回来 同间隔排列
  35.                         k--;
  36.                 }
  37.         }
  38. }
  39. int main()
  40. {
  41.         dfs(0);
  42.         return 0;
  43. }
复制代码
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
16#
 楼主| 发表于 2020-3-21 20:48:07 | 只看该作者
8皇后问题:8*8的国际象棋棋盘,摆8个皇后,相互不攻击,皇后攻击同一行,同一列,正反两斜对角线的子。
搜索,总共8个皇后,每个皇后8个位置可能,满足条件就行,和8选8有相似之处:
void  dfs(int i)
{  
    if(i>9)  pr();
    else for (int k=1;k<=8;k++)
      if (can(i,k))  第i行可以放在第k个位置
       {
            a(i)=k;dfs(i+1);
        }
}
那么重点就在写函数can(i,k) 上
暴力搜索
bool  can(int i,int k)
{  
     bool b=1;
     for (int j=1;j<=i-1;j++)  if a(j)==k  b=0;   前面i-1 行某个和我同列
     for (int j=1;j<=i-1;j++)  if j+a(j)==k+i  b=0;    前面i-1 行某个和我同对角线
     for (int j=1;j<=i-1;j++)  if ???  b=0;   前面i-1 行某个和我同反对角线
  returnb;
}
回复 支持 3 反对 0

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
17#
 楼主| 发表于 2020-3-21 20:51:19 | 只看该作者
这个8皇后请自己完成
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
18#
 楼主| 发表于 2020-3-21 20:53:11 | 只看该作者
所谓因数分解,就是
100=2*50
100=2*2*25
100=4*25
***
所有的分解情况,这个题显然也可以递归
dfs(i)表示把i分解,要是i==1就不能分解了,否则,可以分解出一个j(i%j==0) 然后继续去分解dfs(i/j)。
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5420

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5420
19#
 楼主| 发表于 2020-3-21 20:56:34 | 只看该作者
void  dfs(int i)
if i==1 return
else for (int j=a[x-1];j<=i;j++)  后面的因子大于等于前面一个
  if (i%j==0)  {a[x]=j;dfs(i/j);}
回复 支持 反对

使用道具 举报

0

主题

11

帖子

61

积分

注册会员

Rank: 2

积分
61
20#
发表于 2020-5-9 20:52:19 | 只看该作者
我们还可以用这种方法来算二的一百次方的最少计算次数,和因数分解很像,上代码:
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-11-3 00:29 , Processed in 0.098442 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表