方法一
实际上就是
A
(
9
,
i
)
A(9,i)
A(9,i)的实现,先通过状态的枚举求出子集,然后使用next_permutation()
求出全排列。
const int N = 400000;
class Solution {
public:
pair<int,int> toDot(int x) {
return {x/3,x - x/3*3};
}
bool ok(vector<int>& a) {
bool vis[10] = {0};
vis[a[0]] = 1;
for(int i = 1; i < a.size(); i++) {
auto p1 = toDot(a[i-1]);
auto p2 = toDot(a[i]);
if( abs(p1.first - p2.first) == 2 || abs(p1.second - p2.second) == 2 ) {
double x = (a[i-1] + a[i])/2.0;
if(x == (int)x ) {
if(vis[(int)x] == false) {
return false;
}
}
}
vis[a[i]] = 1;
}
return true;
}
int cal(vector<int>& a) {
int res = 0;
do {
res += ok(a);
}while(next_permutation(a.begin(),a.end()));
return res;
}
int numberOfPatterns(int m, int n) {
if(m > n) return 0;
int limit = 1<<9;
int f[10] = {0};
vector<int> a;
for(int s = 0; s < limit; s++) {
a.clear();
for(int i = 0; i < 9; i++) {
if((s>>i)&1) {
a.push_back(i);
}
}
if(a.size() >= m && a.size() <= n) {
f[a.size()] += cal(a);
}
}
int ans = 0;
for(int i = m; i <= n; i++) {
ans += f[i];
}
return ans;
}
};
方法二
普通的回溯法,主要是判断下棋的合法性需要注意一点。
class Solution {
struct Dot {
int x;
int y;
};
public:
vector<Dot> dots;
bool vis[3][3];
void dfs(Dot d1,int step) {
if(step > n) return;
if(step >= m && step <= n) {
ans++;
}
for(auto d2:dots) {
if(vis[d2.x][d2.y]) continue;
if(abs(d1.x - d2.x) == 2 || abs(d1.y - d2.y) == 2) {
double midX = (d1.x + d2.x)/2.0;
double midY = (d1.y + d2.y)/2.0;
if(midX == (int)midX && midY == (int)midY) {
if(!vis[(int)midX][(int)midY]) continue;
}
}
vis[d2.x][d2.y] = 1;
dfs(d2,step + 1);
vis[d2.x][d2.y] = 0;
}
}
int ans = 0;
int m, n;
int numberOfPatterns(int m, int n) {
this->m = m;
this->n = n;
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
dots.push_back({i,j});
}
}
for(Dot dot:dots) {
memset(vis,0,sizeof(vis));
vis[dot.x][dot.y] = 1;
dfs(dot,1);
}
return ans;
}
};