题目描述
设X是有N个不相同整数的集合。把X中每个数用两次,排成一个长度为2N的数列S,要求S中任意一个数i与另一个与它相同的i之间正好间隔i个数字。
输入输出格式
输入格式
第一行,一个整数N(1≤N≤8)。
第二行,有N个整数(每个数不相同,并且在0到16之间),表示集合中的数。
输出格式
输出一个满足上面要求的长度为2N的数列;如果有多个解,输出字典序最小的解;如果没有解,输出-1。
输入输出样例
输入样例
8
8 0 12 6 2 4 3 13
输出样例
12 13 2 8 3 2 4 6 3 0 0 4 8 12 6 13
题解
暴搜水题,相信随随便都能编出如下的程序。
#include <iostream> #include <algorithm> using namespace std; int n; int a[10]; int f[10]; int s[20]; int ans; void DFS(int dep) { if(dep > n + n) { for(register int i = 1; i < n + n; ++i) { cout << s[i] << " "; } cout << s[n + n]; ans = 1; return; } for(register int i = 1; i <= n; ++i) { if(f[i] == 1 && (dep - a[i] <= 1 || s[dep - a[i] - 1] != a[i]) || f[i] == 2) continue; ++f[i]; s[dep] = a[i]; DFS(dep + 1); if(ans) return; s[dep] = -1; --f[i]; } return; } int main() { cin >> n; for(register int i = 1; i <= n; ++i) { cin >> a[i]; } sort(a + 1, a + n + 1); for(register int i = 1; i <= n + n; ++i) { s[i] = -1; } DFS(1); if(!ans) cout << -1; return 0; }
但实际上这里有一个可以大大减小时间的剪枝要点。
我们其实可以在更改s[dep]的时候顺便更改s[dep+a[i]+1]的值,这样到了s[dep+a[i]+1]的时候就可以直接继续向后搜了。
#include <iostream> #include <algorithm> using namespace std; int n; int a[10]; int f[10]; int s[20]; int ans; void DFS(int dep) { if(dep > n + n) { for(register int i = 1; i < n + n; ++i) { cout << s[i] << " "; } cout << s[n + n]; ans = 1; return; } if(~s[dep]) return DFS(dep + 1); for(register int i = 1; i <= n && dep + a[i] < n + n; ++i) { if(f[i] || ~s[dep + a[i] + 1]) continue; f[i] = 1; s[dep] = s[dep + a[i] + 1] = a[i]; DFS(dep + 1); if(ans) return; s[dep] = s[dep + a[i] + 1] = -1; f[i] = 0; } return; } int main() { cin >> n; for(register int i = 1; i <= n; ++i) { cin >> a[i]; } sort(a + 1, a + n + 1); for(register int i = 1; i <= n + n; ++i) { s[i] = -1; } DFS(1); if(!ans) cout << -1; return 0; }