思路:暴力搜索+剪枝。
1.如何快速判断两个点之间是否隔着其他点?
二维数组打表即可,G[x][y]表示x和y之间隔着的点,如果没有则置为0。
代码:
void init() {
memset(G, 0, sizeof(G));
for(int i = 1; i <= 7; i+=3)
G[i][i+2] = G[i+2][i] = i+1;
for(int i = 1; i <= 3; ++i)
G[i][i+6] = G[i+6][i] = i+3;
G[1][9] = G[9][1] = G[3][7] = G[7][3] = 5;
}
2.剪枝
如果某条边(x,y)的两个端点都被访问过,但是边(x, y)和(y, x)都没有被访问,那么后面也不可能访问到这条边,那么剪枝。
详细代码如下,如有错误或者不懂得地方欢迎留言
#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 10 + 5;
int vis[maxn], ans, n, G[maxn][maxn], e[maxn][maxn];
struct edge{
int x, y;
}a[maxn];
void init() {
memset(G, 0, sizeof(G));
for(int i = 1; i <= 7; i+=3)
G[i][i+2] = G[i+2][i] = i+1;
for(int i = 1; i <= 3; ++i)
G[i][i+6] = G[i+6][i] = i+3;
G[1][9] = G[9][1] = G[3][7] = G[7][3] = 5;
}
void dfs(int u, int cnt) {
//is it possible
for(int i = 0; i < n; ++i) {
int x = a[i].x, y = a[i].y;
if(vis[x] && vis[y] && !e[x][y] && !e[y][x]) return; //一条边的两个端点都被使用,但是这条边没使用则剪枝
}
int flag = 1;
for(int i = 0; i < n; ++i) {
if(!e[a[i].x][a[i].y] && !e[a[i].y][a[i].x]) {
flag = 0;
break;
}
}
if(flag && cnt >= 4) ans++;
for(int i = 1; i <= 9; ++i) {
if(u != i && !vis[i] && vis[G[u][i]]) {
vis[i] = e[u][i] = 1;
dfs(i, cnt+1);
vis[i] = e[u][i] = 0;
}
}
}
int main() {
init();
while(scanf("%d", &n) == 1) {
for(int i = 0; i < n; ++i) scanf("%d%d", &a[i].x, &a[i].y);
ans = 0;
for(int i = 1; i <= 9; ++i) {
memset(vis, 0, sizeof(vis));
memset(e, 0, sizeof(e));
vis[0] = vis[i] = 1;
dfs(i, 1);
}
printf("%d\n", ans);
}
return 0;
}
如有不当之处欢迎指出!