Task: Zumkeller numbers


C++: #include <iostream">
#include <cmath>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <numeric>

using namespace std;


const uint* binary(uint n, uint length);



uint sum_subset_unrank_bin(const vector<uint>& d, uint r);

vector<uint> factors(uint x);

bool isPrime(uint number);

bool isZum(uint n);

ostream& operator<<(ostream& os, const vector<uint>& zumz) {
    for (uint i = 0; i < zumz.size(); i++) {
        if (i % 10 == 0)
            os << endl;
        os << setw(10) << zumz[i] << ' ';
    }
    return os;
}

int main() {
    cout << "First 220 Zumkeller numbers:" << endl;
    vector<uint> zumz;
    for (uint n = 2; zumz.size() < 220; n++)
        if (isZum(n))
            zumz.push_back(n);
    cout << zumz << endl << endl;

    cout << "First 40 odd Zumkeller numbers:" << endl;
    vector<uint> zumz2;
    for (uint n = 2; zumz2.size() < 40; n++)
        if (n % 2 && isZum(n))
            zumz2.push_back(n);
    cout << zumz2 << endl << endl;

    cout << "First 40 odd Zumkeller numbers not ending in 5:" << endl;
    vector<uint> zumz3;
    for (uint n = 2; zumz3.size() < 40; n++)
        if (n % 2 && (n % 10) !=  5 && isZum(n))
            zumz3.push_back(n);
    cout << zumz3 << endl << endl;

    return 0;
}


const uint* binary(uint n, uint length) {
    uint* bin = new uint[length];	    
    fill(bin, bin + length, 0);         
    
    for (uint i = 0; n > 0; i++) {
        uint rem = n % 2;
        n /= 2;
        if (rem)
            bin[length - 1 - i] = 1;
    }

    return bin;
}



uint sum_subset_unrank_bin(const vector<uint>& d, uint r) {
    vector<uint> subset;
    
    const uint* bits = binary(r, d.size() - 1);

    
    for (uint i = 0; i < d.size() - 1; i++)
        if (bits[i])
            subset.push_back(d[i]);

    delete[] bits;

    return accumulate(subset.begin(), subset.end(), 0u);
}

vector<uint> factors(uint x) {
    vector<uint> result;
    
    for (uint i = 1; i * i <= x; i++) {
        
        if (x % i == 0) {
            result.push_back(i);

            if (x / i != i)
                result.push_back(x / i);
        }
    }

    
    sort(result.begin(), result.end());
    return result;
}

bool isPrime(uint number) {
    if (number < 2) return false;
    if (number == 2) return true;
    if (number % 2 == 0) return false;
    for (uint i = 3; i * i <= number; i += 2)
        if (number % i == 0) return false;

    return true;
}

bool isZum(uint n) {
    
    if (isPrime(n))
        return false;

    
    const auto d = factors(n);
    uint s = accumulate(d.begin(), d.end(), 0u);

    
    if (s % 2 || s < 2 * n)
        return false;

    
    
    
    if (n % 2 || d.size() >= 24)
        return true;

    if (!(s % 2) && d[d.size() - 1] <= s / 2)
        for (uint x = 2; (uint) log2(x) < (d.size() - 1); x++) 
            if (sum_subset_unrank_bin(d, x) == s / 2)
                return true; 

    
    return false;
}




Java: import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ZumkellerNumbers {

    public static void main(String[] args) {
        int n = 1;
        System.out.printf("First 220 Zumkeller numbers:%n");
        for ( int count = 1 ; count <= 220 ; n += 1 ) {
            if ( isZumkeller(n) ) {
                System.out.printf("%3d  ", n);
                if ( count % 20 == 0 ) {
                    System.out.printf("%n");
                }
                count++;
            }
        }
        
        n = 1;
        System.out.printf("%nFirst 40 odd Zumkeller numbers:%n");
        for ( int count = 1 ; count <= 40 ; n += 2 ) {
            if ( isZumkeller(n) ) {
                System.out.printf("%6d", n);
                if ( count % 10 == 0 ) {
                    System.out.printf("%n");
                }
                count++;
            }
        }
        
        n = 1;
        System.out.printf("%nFirst 40 odd Zumkeller numbers that do not end in a 5:%n");
        for ( int count = 1 ; count <= 40 ; n += 2 ) {
            if ( n % 5 != 0 && isZumkeller(n) ) {
                System.out.printf("%8d", n);
                if ( count % 10 == 0 ) {
                    System.out.printf("%n");
                }
                count++;
            }
        }

    }
    
    private static boolean isZumkeller(int n) {
        
        if ( n % 18 == 6 || n % 18 == 12 ) {
            return true;
        }
        
        List<Integer> divisors = getDivisors(n);        
        int divisorSum = divisors.stream().mapToInt(i -> i.intValue()).sum();
        
        
        if ( divisorSum % 2 == 1 ) {
            return false;
        }
        
        
        int abundance = divisorSum - 2 * n;
        if ( n % 2 == 1 && abundance > 0 && abundance % 2 == 0 ) {
            return true;
        }
        
        Collections.sort(divisors);
        int j = divisors.size() - 1;
        int sum = divisorSum/2;
        
        
        if ( divisors.get(j) > sum ) {
            return false;
        }
        
        return canPartition(j, divisors, sum, new int[2]);
    }
    
    private static boolean canPartition(int j, List<Integer> divisors, int sum, int[] buckets) {
        if ( j < 0 ) {
            return true;
        }
        for ( int i = 0 ; i < 2 ; i++ ) {
            if ( buckets[i] + divisors.get(j) <= sum ) {
                buckets[i] += divisors.get(j);
                if ( canPartition(j-1, divisors, sum, buckets) ) {
                    return true;
                }
                buckets[i] -= divisors.get(j);
            }
            if( buckets[i] == 0 ) {
                break;
            }
        }
        return false;
    }
    
    private static final List<Integer> getDivisors(int number) {
        List<Integer> divisors = new ArrayList<Integer>();
        long sqrt = (long) Math.sqrt(number);
        for ( int i = 1 ; i <= sqrt ; i++ ) {
            if ( number % i == 0 ) {
                divisors.add(i);
                int div = number / i;
                if ( div != i ) {
                    divisors.add(div);
                }
            }
        }
        return divisors;
    }

}