2016第七届蓝桥杯C/C++B组真题 剪邮票

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 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;
}

猜你喜欢

转载自blog.csdn.net/qq_42835910/article/details/88696826