挑戰程序設計競賽 2.6章習題 poj 3421 X-factor Chains

https://vjudge.net/problem/POJ-3421#author=GPT_zh

Given a positive integer X, an X-factor chain of length m is a sequence of integers,
1 = X0, X1, X2, …, Xm = X

satisfying
Xi < Xi+1 and Xi | Xi+1 where a | b means a perfectly divides into b.

Now we are interested in the maximum length of X-factor chains and the number of chains of such length.

Input
The input consists of several test cases. Each contains a positive integer X (X ≤ 2^20).

Output
For each test case, output the maximum length and the number of such X-factors chains.

2
3
4
10
100

1 1
1 1
2 1
2 2
4 6
給定一個正整數 X,長度爲 m 的 X 因子鏈是一個整數序列,1 = X0, X1, X2, …, Xm = X
滿足Xi < Xi+1 且 Xi | Xi+1,其中 a | b 表示 a 完全整除 b。
現在我們對 X 因子鏈的最大長度和該長度的鏈的數量感興趣。

輸入
輸入包含多個測試用例。每個測試用例包含一個正整數 X (X ≤ 2^20)。

輸出
對於每個測試用例,輸出最大長度和該長度的 X 因子鏈的數量。

2
3
4
10
100

1 1
1 1
2 1
2 2
4 6

解答:
一道好題目 可以用多種方案解決

  1. 分解約數 dp得到最長路徑和最長路徑數目
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>


using namespace std;

vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i++)
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}
int dp[10000][2];
void solve(const vector<int>& v) {
    memset(dp, 0, sizeof dp);

    dp[0][0] = 0; dp[0][1] = 1;
    for (int i = 1; i < v.size(); i++) {
        int vala = v[i];
        for (int j = 0; j < i; j++) {
            int valb = v[j];
            if (vala % valb == 0 && dp[j][0] + 1 > dp[i][0]) {
                dp[i][0] = dp[j][0] + 1;
                dp[i][1] = dp[j][1];
            }
            else if (vala % valb == 0 && dp[j][0] + 1 == dp[i][0]) {
                dp[i][1] += dp[j][1];
            }
        }
    }

    cout << dp[v.size() - 1][0] << " " << dp[v.size() - 1][1] << endl;
    return;
}


int main()
{
    int n;
    while (cin >> n) {
        vector<int> v = get_divisors(n);
        solve(v);
    }


    return 0;
}
  1. 分解質因數 dfs獲得最長路徑的數目
// X-factor Chains POJ - 3421 挑戰編程.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include <iostream>
#include <vector>
using namespace std;

vector<int> primes;

void divide(int x)
{
    for (int i = 2; i <= x / i; i++)
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s++;
            //cout << i << ' ' << s << endl;
            primes.push_back(i);  primes.push_back(s);
        }
    if (x > 1) {
        //cout << x << ' ' << 1 << endl;
        primes.push_back(x);  primes.push_back(1);
    }
    //cout << endl;
}

long long fac(int x) {
    if (x == 1) return 1;
    long long ret = 1;
    ret *= x*fac(x - 1);
    return ret;
}

int ans1 = 0;
long long  ans2 = 0;


void dfs(int x) {
    if (x >= ans1) {
        ans2++;
        return;
    }

    for (int i = 1; i < primes.size(); i += 2) {
        if (primes[i] != 0) {
            primes[i]--;
            dfs(x + 1);
            primes[i]++;
        }
    }

    return;
}


int main()
{
    int n;
    while (cin >> n) {
        primes.clear();
        divide(n);
        ans1 = 0;
        // 選擇所有素因子就是最長路徑 = 素因子的冪和
        for (int i = 1; i < primes.size(); i+=2) {
            ans1 += primes[i];
        }
        ans2 = 0;
        dfs(0);
        cout << ans1 << " " << ans2 << endl;

        /*
        // 素因子的所有冪和的階乘就是所有約數路徑的組合
        // 除以每個素因數的階乘 也就是取出重複的排列組合
        // 最後就是選取所有素因數(最長路徑) 的路徑數目
        ans2 = fac(ans1);   //數據範圍2^20 最多20! long long 即可
        for (int i = 1; i < primes.size(); i+= 2) {
            ans2 = ans2 / fac(primes[i]);
        }

        cout << ans1 << " " << ans2 << endl;
        */
    }


    return 0;
}
  1. 分解質因數 使用排列組合直接得到最長路徑數目
#include <iostream>
#include <vector>

using namespace std;

vector<int> primes;
void divide(int x)
{
    for (int i = 2; i <= x / i; i++)
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s++;
            //cout << i << ' ' << s << endl;
            primes.push_back(i);  primes.push_back(s);
        }
    if (x > 1) {
        //cout << x << ' ' << 1 << endl;
        primes.push_back(x);  primes.push_back(1);
    }
    //cout << endl;
}

long long fac(int x) {
    if (x == 1) return 1;
    long long ret = 1;
    ret *= x*fac(x - 1);
    return ret;
}

int main()
{
    int n;
    while (cin >> n) {
        primes.clear();
        divide(n);
        int ans1 = 0;
        // 選擇所有素因子就是最長路徑
        for (int i = 1; i < primes.size(); i+=2) {
            ans1 += primes[i];
        }
       
        // 素因子的所有冪和的階乘就是所有約數路徑的組合
        // 除以每個素因數的階乘 也就是取出重複的排列組合
        // 最後就是選取所有素因數(最長路徑) 的路徑數目
        long long ans2 = fac(ans1);   //數據範圍2^20 最多20! long long 即可
        for (int i = 1; i < primes.size(); i+= 2) {
            ans2 = ans2 / fac(primes[i]);
        }

        cout << ans1 << " " << ans2 << endl;
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章