Codeforces 337E Divisor Tree 暴搜

题目大意:

就是现在给出最多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;
}


你可能感兴趣的:(Codeforces 337E Divisor Tree 暴搜)