剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
解:因为是填空题,不考虑效率的情况之下解法就很多,保证正确即可。我用的是回溯的方法,将得到的解(5个整数)按字典序排列为一个string,然后放入一个set中,可以去重,最终的结果就是set 的size咯,answer:112
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
bool valid[12];
set<string> result;
void find(vector<int> &now) {
int size = now.size();
if (size == 5) {
string a = "";
for (int i = 0; i < 12; i++)
if (!valid[i]) a += i+48;
result.insert(a);
return;
}
int latest = now[size-1];
for (int i = 0; i < size; i++) {
int latest = now[i];
if (latest > 3 && valid[latest-4]) {
now.push_back(latest-4);
valid[latest-4] = false;
find(now);
now.pop_back();
valid[latest-4] = true;
}
if (latest < 8 && valid[latest+4]) {
now.push_back(latest+4);
valid[latest+4] = false;
find(now);
now.pop_back();
valid[latest+4] = true;
}
if (latest % 4 != 0 && valid[latest-1]) {
now.push_back(latest-1);
valid[latest-1] = false;
find(now);
now.pop_back();
valid[latest-1] = true;
}
if (latest % 4 != 3 && valid[latest+1]) {
now.push_back(latest+1);
valid[latest+1] = false;
find(now);
now.pop_back();
valid[latest+1] = true;
}
}
}
int main() {
for (int i = 0; i < 12; i++) valid[i] = true;
vector<int> now;
for (int i = 0; i < 12; i++) {
now.push_back(i);
valid[i] = false;
find(now);
now.pop_back();
valid[i] = true;
}
cout << result.size();
}