题目:
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:从14个数中枚举所有5位数的组合(跳过5和10,便于后序判断),再判断是否是一组合法的组合。
代码:
#include <bits/stdc++.h>
using namespace std;
const int M = 5;
const int N = 15;
int an[M];
int visited[N];
int avis[N];
int cnt(0),xcnt(0);
int dir[4] = {-1,1,5,-5};
void walk(int n)
{
for(int i=0;i<4;++i) {
int tn = n+dir[i];
if(tn<1||tn>14||tn==5||tn==10) continue;
for(int j=0;j<M;++j) {
int item = an[j];
if(item==tn&&!avis[tn]) {
avis[tn] = 1;
xcnt += 1;
walk(tn);
}
}
}
}
bool islegal()
{
for(int i=1;i<M;++i) {
if(an[i]<an[i-1]) return false;
}
memset(avis,0,sizeof(int)*N);
xcnt = 1;
avis[an[0]] = 1;
walk(an[0]);
if(xcnt==5) return true;
return false;
}
void dfs(int m)
{
if(m==0) {
if(islegal()){
cnt += 1;
for(int i=0;i<M;++i) cout << an[i] << ends;
cout << endl;
}
return;
}
for(int i=1;i<N;++i) {
if(!visited[i]&&i!=5&&i!=10) {
an[M-m] = i;
visited[i]=1;
dfs(m-1);
visited[i]=0;
}
}
}
int main()
{
memset(visited,0,sizeof(int)*N);
dfs(M);
cout << cnt << endl;
return 0;
}