版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/qq_42835910/article/details/88696826
如【图1.jpg】, 有12张连在一起的12生肖的邮票。 现在你要从中剪下5张来,要求必须是连着的。 (仅仅连接一个角不算相连) 比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。 请你计算,一共有多少种不同的剪取方法。 请填写表示方案数目的整数。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
ans : 116
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int dx[4] = {0,-1,0,1}, dy[4] = {1,0,-1,0};
int a[10][10], num[100], use[100], t[100], cnt = 0, ans = 0;
vector<int> g[15];
void dfs(int u){
use[u] = false;
cnt++;
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if( use[v] ) dfs(v);
}
}
void solve(){
cnt = 0;
memset(use, 0 ,sizeof(use));
for(int i = 0; i < 5; i++)
use[ t[i]] = 1; //标记使用,便于dfs统计。
dfs(t[0]);
if(cnt == 5) ans++;
}
int main(int argc, char** argv) {
int cnt = 1;
for(int i = 1; i <= 3; i++)
for(int j = 1; j <= 4; j++)
a[i][j] = cnt++;
for(int i = 1; i <= 3; i++){ //相邻构图,便于统计
for(int j = 1; j <= 4; j++){
for(int k = 0; k < 4; k++){
int nx = i+dx[k],ny = j+dy[k];
if(a[nx][ny] != 0)
g[a[i][j]].push_back(a[nx][ny]);
}
}
}
for(int i = 0, len = 1 << 20; i < len; i++ ){ //2进制枚举子集
int cnt = 0;
for(int j = 0; j < 20; j++){
if( i & (1 << j)){ //获取第j位二进制是否为1.标志选取
t[cnt++] = j+1;
if(cnt > 5) break;
}
}
if( cnt == 5) solve();//子集长度刚好为5,进入统计
}
cout<< ans << endl;
return 0;
}