华师一附中OI组
标题:
20200307 pmn讲课
[打印本页]
作者:
admin
时间:
2020-3-7 19:23
标题:
20200307 pmn讲课
1、m个中选n个的基本程序:
#include <iostream>
using namespace std;
const int mn=10;
const int mm=20; ///m中选 n
int a[mn];
bool b[mm];
int m,n,i;
void pr()
{
for (int i=1; i<=n; i++) cout<<a[i];
cout<<endl;
}
void dfs(int i) /// 寻找第i的位置上的数
{
if (i>n) pr();
else for (int k=1; k<=m; k++)
if (b[k]==1)
{
a[i]=k; /// 选择
b[k]=0; ///标记
dfs(i+1); ///选下一个
b[k]=1; ///复位
}
}
int main()
{
m=8,n=5; ///假设8选5
for (int i=1; i<=mm-1; i++) b[i]=1; ///标记可选
dfs(1); ///从第一个开始
return 0;
}
复制代码
作者:
admin
时间:
2020-3-7 19:27
2、改成m个中选n个组合 ,组合不讲顺序,所以123也就是321,312。
转换点:强制认为后面比前面大,就限制了一些重复的选择。
改动:
1、k的取值 不是从1开始,而是要比前面大,所以从a[i-1]+1开始
2、因为后面比前面大,所以绝对不会重复,所以不需要b数组。
程序如下:
#include <iostream>
using namespace std;
const int mn=10;
const int mm=20; ///m中选 n
int a[mn];
bool b[mm];
int m,n,i;
void pr()
{
for (int i=1; i<=n; i++) cout<<a[i];
cout<<endl;
}
void dfs(int i) /// 寻找第i的位置上的数
{
if (i>n) pr();
else for (int k=a[i-1]+1; k<=m; k++)
///if (b[k]==1)
{
a[i]=k; /// 选择
/// b[k]=0; ///标记
dfs(i+1); ///选下一个
/// b[k]=1; ///复位
}
}
int main()
{
m=8,n=5; ///假设8选5
///for (int i=1; i<=mm-1; i++) b[i]=1; ///标记可选
a[0]=0 ; /// 最好加上,因为a[1-1]没有初值
dfs(1); ///从第一个开始
return 0;
}
复制代码
作者:
admin
时间:
2020-3-7 19:30
3、m个中选任意个的组合,
改动if (i>n) 这个地方。因为这里控制着输出,不是到n输出,而是任意个都要输出
#include <iostream>
using namespace std;
const int mn=10;
const int mm=20; ///m中选 n
int a[mn];
bool b[mm];
int m,n,i;
void pr(int i)
{
for (int j=1; j<=i-1; j++) cout<<a[j];
cout<<endl;
}
void dfs(int i) /// 寻找第i的位置上的数
{
pr(i); ///要加一个参数
for (int k=a[i-1]+1; k<=m; k++)
///if (b[k]==1)
{
a[i]=k; /// 选择
/// b[k]=0; ///标记
dfs(i+1); ///选下一个
/// b[k]=1; ///复位
}
}
int main()
{
m=8,n=5; ///假设8选5
///for (int i=1; i<=mm-1; i++) b[i]=1; ///标记可选
a[0]=0 ; /// 最好加上,因为a[1-1]没有初值
dfs(1); ///从第一个开始
return 0;
}
复制代码
而且这里pr函数还有一个细节,加一个参数。这是编程基本功,你会吗?
作者:
admin
时间:
2020-3-7 19:50
4、有重复怎么办?假设111223455中选3个,有多少种组合的选法。
重复的时候,不要用布尔数组,改用整数数组,用一个少一个而不是用和不用两种状态!
#include <iostream>
using namespace std;
int a[10];///存放选后的数字
int b[6]= {0,3,2,1,1,2}; ///表示有几个选择 不是一个
void pr()
{
for(int i=1; i<=3; i++) cout<<a[i]<<' ';
cout<<endl;
}
void pmn(int i)
{
if(i>3)pr();
else
for(int k=a[i-1]; k<=5; k++)
if(b[k]>0)
{
a[i]=k;
b[k]--;
pmn(i+1);
b[k]++;
}
}
int main()
{
a[0]=1;
pmn(1);
return 0;
}
复制代码
注意这里又有个问题,是可以重复的,所以后面选出来的数可以和前面一样,k的初值就是a(i),而不是前面那样的a(i-1)+1,完美的话还要赋初值a(0)=1;
作者:
admin
时间:
2020-3-7 20:22
5、1-8八个数字排成一排,相邻两个数之差的绝对值<4。怎么办?
增加一个条件,除第一个之外,|a(i)-a(i-1)|<4
但是这个条件写起来不简单 应该是 : (i==1) || (|a(i)-a(i-1)|<4) 隐含了一个条件 i==1
作者:
admin
时间:
2020-3-7 20:23
6、11223344排成一排,两个1之间隔1个数字,两个2之间隔2个数字,**,求所有的排法。
这个题的放置条件更复杂。
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2