next_permutation()组合数枚举
describe
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
//116
解析
用C(12,5)的枚举组合数, 可用next_permutation()枚举, next_permutation()可以已经做了对相同的数枚举时的处理,
如前面的几个0互相调换位置, 是同一种组合数, 真的是个很强大的函数啊! ! !
这里的组合数可以用降维数组, 将二维的数组映射到一维上, 如g[ 2 ][ 0 ] —>a[ 2*4+0 ] —> a[ 8 ]. 对a 进行全排列
对每一种排列进行dfs 搜索处理, 可以参考岛屿数量的题. 并计数.
c++代码
#include<bits/stdc++.h>
using namespace std;
//对二维数组进行dfs处理, 本来访问完毕后应该还原成0, 这里直接顺便还原成0
void dfs(int i,int j,int g[3][4]){
if(i<0||j<0||i>=3||j>=4)return;
if(g[i][j]==0)return;
g[i][j] = 0;
dfs(i+1,j,g);
dfs(i-1,j,g);
dfs(i,j+1,g);
dfs(i,j-1,g);
}
//检查
bool check(int g[3][4]){
int cnt=0;
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(g[i][j]==1){
dfs(i,j,g);
cnt++;
}
}
}
return cnt==1;
}
//重要的数组!!!
//组合数的选取C(12,5)
int a[]={0,0,0,0,0,0,0,1,1,1,1,1};
//变量定义在全局, 默认初始化
int g[3][4];
int main(){
int cnt=0;
do{
//根据a[]来初始化g[][]
for(int i=0;i<3;i++){
for(int j=0;j<4;j++){
if(a[i*4+j])g[i][j]=1;
}
}
if(check(g))cnt++;
//对每一种C(12,5)的选取进行判断
}while(next_permutation(a,a+12));
cout<<cnt;
return 0;
}
!!!
这题表示我看了视频之后, 然后一下按照视频的思路写, 居然没有错误的一下就写出dfs的题来了, 真的开心啊, 是我第一次写
dfs的代码一次就写对的, 纪念一下嘿嘿! 也许是这题简单吧, 所以才能吧, 还是因为我背下来了 ? ( 雾 ) . 或许是
视频讲的好吧( 😃 )
此时想到的是对集合的子集该如何枚举.