题意:画图案所的问题,给出一个3 × 3拨号盘中的几个数字作为活跃点,问由活跃点能组合多少种解锁方式,并输出它们。一个合法的解锁方式包含以下几点:
- 一个方案中由一些点构成,每个点在按顺序触摸的时候都是第一次被触摸到,称这些点为活跃点。
- 如果在连接A,B两点的时候经过了另外的点,那么这个点必须出现在序列中,并且在A和B之前出现。
- 一个点被合法的线段多次通过是可以的,只要这个点在之前合法出现过。
解法:枚举排列,挨个判断是否合法,因为之前读错过题……所以写的比较啰嗦……正常应该不是很难写……就不介绍我的写法了……(捂脸
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
int n;
int pass[10][10];
void init()
{
memset(pass, 0, sizeof(pass));
pass[1][3] = 2;
pass[3][1] = 2;
pass[1][7] = 4;
pass[7][1] = 4;
pass[3][9] = 6;
pass[9][3] = 6;
pass[7][9] = 8;
pass[9][7] = 8;
pass[2][8] = pass[3][7] = pass[1][9] = pass[4][6] = pass[8][2] = pass[7][3] = pass[9][1] = pass[6][4] = 5;
}
vector <vector <int> > res;
bool judge(int a[10], int vis[10])
{
int new_vis[10];
memcpy(new_vis, vis, sizeof(new_vis));
new_vis[a[0]] = false;
for(int i = 1; i < n; i++)
{
if(!new_vis[a[i]])
return false;
//cout << pass[a[i - 1]][a[i]] << endl;
if(pass[a[i - 1]][a[i]] && new_vis[pass[a[i - 1]][a[i]]] == -1)
return false;
new_vis[pass[a[i - 1]][a[i]]] = 0;
new_vis[a[i]] = 0;
}
return true;
}
int main()
{
int T;
while(~scanf("%d", &T))
{
init();
while(T--)
{
res.clear();
scanf("%d", &n);
int a[10];
int vis[10];
memset(vis, -1, sizeof(vis));
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
vis[a[i]] = 1;
}
sort(a, a + n);
int ans = 0;
do
{
if(judge(a, vis))
{
ans++;
vector <int> tmp;
for(int i = 0; i < n; i++)
tmp.push_back(a[i]);
res.push_back(tmp);
}
}while(next_permutation(a, a + n));//枚举排列
printf("%d\n", ans);
for(int i = 0; i < ans; i++)
{
for(int j = 0; j < n; j++)
{
if(j)
printf(" ");
printf("%d", res[i][j]);
}
puts("");
}
}
}
return 0;
}