题目大意:
就是现在给出最多8个数(2 <= ai <= 10^12), 问按照题意建立一个divisor tree, 该tree至少有几个节点
大致思路:
就是一个平常的暴搜问题, 细节和注意的地方写在代码注释里了, 具体看代码吧
代码如下:
Result : Accepted Memory : 4 KB Time : 30 ms
/* * Author: Gatevin * Created Time: 2015/3/3 21:06:10 * File Name: Shana.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; /* * 首先可以发现一个事实, 就是在生成的divisor树中叶子节点一定是质数 * 那么a[i]出现的位置可能是叶子节点当且仅当a[i]是质数 * 另外可以发现所有非根节点和叶子节点的位置一定都是a数组中的数, 这样才能保证节点数最小 * 而且当a[i]最为a[j]的子节点的时候, 相当于a[i]的所有质因数叶子节点替代了a[j]的一部分 * 也就是说, 最终叶子节点的个数取决于与根节点相连的数的divisors, 当然这包括了质数的a[i] * 所以需要减去a[i]中质数的个数防止重复计数 * 还有一点要考虑的是根节点的问题, 我们刚开始可以虚拟根节点是0, 所有数都被0整除可以连在根节点上 * 但是当根节点上直连接一个点的时候可以去掉根节点, 否则要用一个连在根节点上的所有节点的积来 * 代替根节点的0, 这样对于从大到小的每一个数, 都可以选择接在根节点后或者其倍数后面 * dfs一下寻找最优解即可, 复杂度O(n!) */ const int inf = 1e9 + 7; int n; lint a[10]; int divisors[10];//表示a[i]的质因子个数 vector <lint> tree;//树上的节点tree[1]是根0 int prime_cnt;//a[i]中的质数个数 /* * now表示开始考虑a数组中的第i个数(从n到1) * ai_with_roots表示与根节点相连的a[i]的数量 * divisors_cnt表示和根节点相连的a[i]的divisor[i]的和 * 同时也是叶子节点数(重复计了质数a[i]) */ int dfs(int now, int ai_with_roots, int divisors_cnt) { if(now == 0) return n + (ai_with_roots > 1) + divisors_cnt - prime_cnt; int ret = inf; for(unsigned int i = 0; i < tree.size(); i++) { if(tree[i] % a[now] == 0) { tree[i] /= a[now];//now接在tree[i]之后tree[i]要剩下一部分供其它可能的接入 tree.push_back(a[now]); ret = min(ret, dfs(now - 1, ai_with_roots + (i == 0), divisors_cnt + (i == 0 ? divisors[now] : 0))); tree[i] *= a[now]; tree.pop_back(); } } return ret; } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%I64d", a + i); sort(a + 1, a + n + 1); for(int i = n; i > 0; i--) { lint ta = a[i]; for(lint j = 2; j * j <= ta; j++) { while(ta % j == 0) { ta /= j; divisors[i]++; } } if(ta > 1) divisors[i]++; if(divisors[i] == 1) prime_cnt++; } tree.push_back(0); printf("%d\n", dfs(n, 0, 0)); return 0; }