Here is the problem (Summation of Four Primes) states that :
The input contains one integer number N (N<=10000000) in every line. This is the number you will have to express as a summation of four primes
Sample Input: 24 36 46
Sample Output: 3 11 3 7 3
7 13 13 11 11 17 7
This idea comes to my mind at a first glance
Find all primes below N
Find length of list (.length = 4) with Integer Partition problem (Knapsack)
but complexity is very bad for this algorithm I think. This problem also looks like Goldbach's_conjecture
more. How can I solve this problem?
This problem has a simple trick.
You can express all numbers as 3+2 + "summation of two primes"
or
2 + 2 + "summation of two primes"
depending on parity of the number.
for the "summation of two primes", use Goldbach's Conjecture.
There are around 700 thousand primes below 10 million.
If the number is even reduce 2 x 2 from it and if odd reduce 2 + 3 from it and finding the other two primes is not difficult because of Goldbach conjecture.
You can implement it by the following code it save a lot of time in your program by make to digit as constant 2 & 2 or 2 & 3 :
int isPrime(int x) {
int s = sqrt(x);
for (int i = 2; i <= s; i++) {
if (x % i == 0) {
return 0;
}
}
return 1;
}
void Num(int x, int & a, int & b) {
for (int i = 2; i <= x / 2; i++) {
if (isPrime(i) && isPrime(x - i)) {
a = i;
b = x - i;
return;
}
}
}
int main() {
int n;
while (cin >> n) {
if (n <= 7) {
cout << "Impossible." << endl;
continue;
}
if (n % 2 !=0) {
int a, b;
Num(n -5, a, b);
cout << "2 3 " << a << " " << b << endl;
}
else {
int a, b;
Num(n -4, a, b);
cout << "2 2 " << a << " " << b << endl;
}
}
return 0;
}
Related
You are given an integer N. You have to find smallest multiple of N which consists of digits 0 and 1 only. Since this multiple could be large, return it in form of a string.
Returned string should not contain leading zeroes.
For example,
For N = 55, 110 is smallest multiple consisting of digits 0 and 1.
For N = 2, 10 is the answer.
I saw several related problems, but I could not find the problem with my code.
Here is my code giving TLE on some cases even after using map instead of set.
#define ll long long
int getMod(string s, int A)
{
int res=0;
for(int i=0;i<s.length();i++)
{
res=res*10+(s[i]-'0');
res%=A;
}
return res;
}
string Solution::multiple(int A) {
if(A<=1)
return to_string(A);
queue<string>q;
q.push("1");
set<int>st;
string s="1";
while(!q.empty())
{
s=q.front();
q.pop();
int mod=getMod(s,A);
if(mod==0)
{
return s;
}
else if(st.find(mod)==st.end())
{
st.insert(mod);
q.push(s+"0");
q.push(s+"1");
}
}
}
Here is an implementation in Raku.
my $n = 55;
(1 .. Inf).map( *.base(2) ).first( * %% $n );
(1 .. Inf) is a lazy list from one to infinity. The "whatever star" * establishes a closure and stands for the current element in the map.
base is a method of Rakus Num type which returns a string representation of a given number in the wanted base, here a binary string.
first returns the current element when the "whatever star" closure holds true for it.
The %% is the divisible by operator, it implicitly casts its left side to Int.
Oh, and to top it off. It's easy to parallelize this, so your code can use multiple cpu cores:
(1 .. Inf).race( :batch(1000), :degree(4) ).map( *.base(2) ).first( * %% $n );
As mentioned in the "math" reference, the result is related to the congruence of the power of 10 modulo A.
If
n = sum_i a[i] 10^i
then
n modulo A = sum_i a[i] b[i]
Where the a[i] are equal to 0 or 1, and the b[i] = (10^i) modulo A
Then the problem is to find the minimum a[i] sequence, such that the sum is equal to 0 modulo A.
From a graph a point of view, we have to find the shortest path to zero modulo A.
A BFS is generally well adapted to find such a path. The issue is the possible exponential increase of the number of nodes to visit. Here, were are sure to get a number of nodes less than A, by rejecting the nodes, the sum of which (modulo A) has already been obtained (see vector used in the program). Note that this rejection is needed in order to get the minimum number at the end.
Here is a program in C++. The solution being quite simple, it should be easy to understand even by those no familiar with C++.
#include <iostream>
#include <string>
#include <vector>
struct node {
int sum = 0;
std::string s;
};
std::string multiple (int A) {
std::vector<std::vector<node>> nodes (2);
std::vector<bool> used (A, false);
int range = 0;
int ten = 10 % A;
int pow_ten = 1;
if (A == 0) return "0";
if (A == 1) return "1";
nodes[range].push_back (node{0, "0"});
nodes[range].push_back (node{1, "1"});
used[1] = true;
while (1) {
int range_new = (range + 1) % 2;
nodes[range_new].resize(0);
pow_ten = (pow_ten * ten) % A;
for (node &x: nodes[range]) {
node y = x;
y.s = "0" + y.s;
nodes[range_new].push_back(y);
y = x;
y.sum = (y.sum + pow_ten) % A;
if (used[y.sum]) continue;
used[y.sum] = true;
y.s = "1" + y.s;
if (y.sum == 0) return y.s;
nodes[range_new].push_back(y);
}
range = range_new;
}
}
int main() {
std::cout << "input number: ";
int n;
std::cin >> n;
std::cout << "Result = " << multiple(n) << "\n";
return 0;
}
EDIT
The above program is using a kind of memoization in order to speed up the process but for large inputs memory becomes too large.
As indicated in a comment for example, it cannot handle the case N = 60000007.
I improved the speed and the range a little bit with the following modifications:
A function (reduction) was created to simplify the search when the input number is divisible by 2 or 5
For the memorization of the nodes (nodes array), only one array is used now instead of two
A kind of meet-in-the middle procedure is used: in a first step, a function mem_gen memorizes all relevant 01 sequences up to N_DIGIT_MEM (=20) digits. Then the main procedure multiple2 generates valid 01 sequences "after the 20 first digits" and then in the memory looks for a "complementary sequence" such that the concatenation of both is a valid sequence
With this new program the case N = 60000007 provides the good result (100101000001001010011110111, 27 digits) in about 600ms on my PC.
EDIT 2
Instead of limiting the number of digits for the memorization in the first step, I now use a threshold on the size of the memory, as this size does not depent only on the number of digits but also of the input number. Note that the optimal value of this threshold would depend of the input number. Here, I selected a thresholf of 50k as a compromise. With a threshold of 20k, for 60000007, I obtain the good result in 36 ms. Besides, with a threshold of 100k, the worst case 99999999 is solved in 5s.
I made different tests with values less than 10^9. In about all tested cases, the result is provided in less that 1s. However, I met a corner case N=99999999, for which the result consists in 72 consecutive "1". In this particular case, the program takes about 6.7s. For 60000007, the good result is obtained in 69ms.
Here is the new program:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <chrono>
#include <cmath>
#include <algorithm>
std::string reverse (std::string s) {
std::string res {s.rbegin(), s.rend()};
return res;
}
struct node {
int sum = 0;
std::string s;
node (int sum_ = 0, std::string s_ = ""): sum(sum_), s(s_) {};
};
// This function simplifies the search when the input number is divisible by 2 or 5
node reduction (int &X, long long &pow_ten) {
node init {0, ""};
while (1) {
int digit = X % 10;
if (digit == 1 || digit == 3 || digit == 7 || digit == 9) break;
switch (digit) {
case(0):
X /= 10;
break;
case(2):
case(4):
case(6):
case(8):
X = (5*X)/10;
break;
case(5):
X = (2*X)/10;
break;
}
init.s.push_back('0');
pow_ten = (pow_ten * 10) % X;
}
return init;
}
const int N_DIGIT_MEM = 30; // 20
const int threshold_size_mem = 50000;
// This function memorizes all relevant 01 sequences up to N_DIGIT_MEM digits
bool gene_mem (int X, long long &pow_ten, int index_max, std::map<int, std::string> &mem, node &result) {
std::vector<node> nodes;
std::vector<bool> used (X, false);
bool start = true;
for (int index = 0; index < index_max; ++index){
if (start) {
node x = {int(pow_ten), "1"};
nodes.push_back (x);
} else {
for (node &x: nodes) {
x.s.push_back('0');
}
int n = nodes.size();
for (int i = 0; i < n; ++i) {
node y = nodes[i];
y.sum = (y.sum + pow_ten) % X;
y.s.back() = '1';
if (used[y.sum]) continue;
used[y.sum] = true;
if (y.sum == 0) {
result = y;
return true;
}
nodes.push_back(y);
}
}
pow_ten = (10 * pow_ten) % X;
start = false;
int n_mem = nodes.size();
if (n_mem > threshold_size_mem) {
break;
}
}
for (auto &x: nodes) {
mem[x.sum] = x.s;
}
//std::cout << "size mem = " << mem.size() << "\n";
return false;
}
// This function generates valid 01 sequences "after the 20 first digits" and then in the memory
// looks for a "complementary sequence" such that the concatenation of both is a valid sequence
std::string multiple2 (int A) {
std::vector<node> nodes;
std::map<int, std::string> mem;
int ten = 10 % A;
long long pow_ten = 1;
int digit;
if (A == 0) return "0";
int X = A;
node init = reduction (X, pow_ten);
if (X != A) ten = ten % X;
if (X == 1) {
init.s.push_back('1');
return reverse(init.s);
}
std::vector<bool> used (X, false);
node result;
int index_max = N_DIGIT_MEM;
if (gene_mem (X, pow_ten, index_max, mem, result)) {
return reverse(init.s + result.s);
}
node init2 {0, ""};
nodes.push_back(init2);
while (1) {
for (node &x: nodes) {
x.s.push_back('0');
}
int n = nodes.size();
for (int i = 0; i < n; ++i) {
node y = nodes[i];
y.sum = (y.sum + pow_ten) % X;
if (used[y.sum]) continue;
used[y.sum] = true;
y.s.back() = '1';
if (y.sum != 0) {
int target = X - y.sum;
auto search = mem.find(target);
if (search != mem.end()) {
//std::cout << "mem size 2nd step = " << nodes.size() << "\n";
return reverse(init.s + search->second + y.s);
}
}
nodes.push_back(y);
}
pow_ten = (pow_ten * ten) % X;
}
}
int main() {
std::cout << "input number: ";
int n;
std::cin >> n;
std::string res;
auto t1 = std::chrono::high_resolution_clock::now();
res = multiple2(n),
std::cout << "Result = " << res << " ndigit = " << res.size() << std::endl;
auto t2 = std::chrono::high_resolution_clock::now();
auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
std::cout << "time = " << duration2/1000 << " ms" << std::endl;
return 0;
}
For people more familiar with Python, here is a converted version of #Damien's code. Damien's important insight is to strongly reduce the search tree, taking advantage of the fact that each partial sum only needs to be investigated once, namely the first time it is encountered.
The problem is also described at Mathpuzzle, but there they mostly fix on the necessary existence of a solution. There's also code mentioned at the online encyclopedia of integer sequences. The sage version seems to be somewhat similar.
I made a few changes:
Starting with an empty list helps to correctly solve A=1 while simplifying the code. The multiplication by 10 is moved to the end of the loop. Doing the same for 0 seems to be hard, as log10(0) is minus infinity.
Instead of alternating between nodes[range] and nodes[new_range], two different lists are used.
As Python supports integers of arbitrary precision, the partial results could be stored as decimal or binary numbers instead of as strings. This is not yet done in the code below.
from collections import namedtuple
node = namedtuple('node', 'sum str')
def find_multiple_ones_zeros(A):
nodes = [node(0, "")]
used = set()
pow_ten = 1
while True:
new_nodes = []
for x in nodes:
y = node(x.sum, "0" + x.str)
new_nodes.append(y)
next_sum = (x.sum + pow_ten) % A
y = node((x.sum + pow_ten) % A, x.str)
if next_sum in used:
continue
used.add(next_sum)
y = node(next_sum, "1" + x.str)
if next_sum == 0:
return y.str
new_nodes.append(y)
pow_ten = (pow_ten * 10) % A
nodes = new_nodes
I've implemented a Kolakoski's sequence with a low memory footprint, using the reference from Wikipedia
#include <iostream>
#include <iomanip>
#include <vector>
int IncrementPointer(std::vector<int>& vec, int k)
{
if (vec.size() <= k)
{
vec.push_back(22);
}
if (vec[k] == 11)
{
vec[k] = 1;
return 1;
}
else if (vec[k] == 22)
{
vec[k] = 2;
return 2;
}
else if (vec[k] == 1)
{
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 2 : 22;
return 2;
}
else if (vec[k] == 2)
{
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 1 : 11;
return 1;
}
return 0;
}
int main()
{
long long iteration = 2;
long long nextPowOf10 = 10;
long long numOf1s = 1;
std::vector<int> vec;
std::cout << std::setw(15) << 'n' << std::setw(15) << "#1s" << std::setw(8) << "P(n)\n";
std::cout << std::setw(15) << 1 << std::setw(15) << numOf1s << '\n';
while (iteration++ <= 100'000'000'000'000)
{
int retvalue = IncrementPointer(vec, 0);
if (retvalue == 1)
++numOf1s;
if (iteration % nextPowOf10 == 0)
{
std::cout << std::setw(15) << nextPowOf10 << std::setw(15) << numOf1s << std::setw(8) << vec.size() << '\n';
nextPowOf10 *= 10;
}
}
return 0;
}
Now, the program internally calculates right elements of the sequence in Debug Mode and outputs expected results. So far, so good.
The problem starts in Release mode, vector gets optimized away (how could it be?), and the elements calculated are now wrong.
The expected sequence is [[1 2] 2 1 1 2 1 2 2 etc.], with first two are preset.
and in release mode the elements are [1 2] 2 1 1 1 1 1 2 ... Clearly, something wrong went on. And subsequently the output is unexpected, and the program crashes, with calling to malloc (so it does have somewhere vector reallocated).
What am I doing wrong? Is it simultaneous push_back to vector and update to the element of vector?
I believe a construct like this exhibits undefined behavior:
vec[k] = IncrementPointer(vec, k + 1) == 1 ? 2 : 22;
It is unspecified whether vec[k] or IncrementPointer(vec, ...) gets evaluated first. vec[k] returns a reference to the corresponding element. If IncrementPointer is called later, it may push new elements into vec which in turn may cause it to reallocate, whereupon that reference becomes dangling.
Make it
int val = IncrementPointer(vec, k + 1);
vec[k] = val == 1 ? 2 : 22;
I have a set of n case in the format a b what I have to do is I have to form number of distinct combination of numbers from a,b. for e.g.,
suppose n=4 and a,b are are follow
1 2
3 1
2 4
3 2
Now total there are 4 distinct number by seeing a,b, they are(1,2,3,4)
and two combination of all distinct numbers can be formed, they are (1,3,4,2) and (2,1,4,3) as follow :-
1 2
|
3 1
\
2 4
|
3 2
and
1 2
|
3 1
|
2 4
/
3 2
My problem is I am unable to think how to code, as n<=50 and a,b<=16 so I am not sure that how many distinct number can be there, if there are 16 numbers then I have to find all possible combination of 16 numbers, so guide me through this.
To form a list of distinct numbers just use a "unique set" and keep inserting all the numbers to it. In C++, std::set by definition stores only unique numbers.
To find the number of combinations of distinct sequences, you will have to keep a list of "candidate lists" and keep inserting numbers in them if they already don't have those numbers, else delete that particular candidate list.
Full code in C++:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main() {
int n = 4;
set<int> uniqueNumbers; // ordered set of unique numbers
vector< set<int> > possibleLists( 1 );
set<int>::iterator it;
for ( int i = 0; i < n; i++ ) {
int num1;
int num2;
cin >> num1 >> num2;
// numbers will be inserted if not already present in set (by definition)
uniqueNumbers.insert( num1 );
uniqueNumbers.insert( num2 );
// make a copy for a possible new branch
vector< set<int> > possibleListsCopy( possibleLists );
//int size1 = possibleLists.size();
for ( int j = 0; j < possibleLists.size(); j++ ) {
it = possibleLists[j].find( num1 );
if ( it == possibleLists[j].end() ) {
possibleLists[j].insert( num1 ); // insert if not found
//cout << "inserted1 "<<endl;
}
else {
// erase this possible combination
possibleLists[j].clear();
possibleLists.erase( possibleLists.begin() + j );
j--;
}
}
//int size2 = possibleListsCopy.size();
for ( int j = 0; j < possibleListsCopy.size(); j++ ) {
;
it = possibleListsCopy[j].find( num2 );
if ( it == possibleListsCopy[j].end() ) {
possibleListsCopy[j].insert( num2 ); // insert if not found
}
else {
// erase this possible combination
possibleListsCopy[j].clear();
possibleListsCopy.erase( possibleListsCopy.begin() + j );
j--;
}
}
// concatenate both set of lists.
possibleLists.insert( possibleLists.end(),
possibleListsCopy.begin(),
possibleListsCopy.end() );
}
cout << " The unique list: ";
//output the unique list.
for ( it = uniqueNumbers.begin(); it != uniqueNumbers.end(); it++ )
cout << *it << " ";
/*cout << endl << endl;
cout << "Possible Lists:" << endl;
for ( int i = 0; i < possibleLists.size(); i++ ) {
for ( it = possibleLists[i].begin(); it != possibleLists[i].end(); it++ )
cout << *it << " ";
cout << endl;
}*/
cout << endl << "Total number of combinations: "
<< possibleLists.size() << endl;
return 0;
}
Input:
1 2
3 1
2 4
3 2
Output:
The unique list: 1 2 3 4
Total number of combinations: 2
Recursion is probably the easiest route when solving combinatorial problems like this one. The idea is that you consider all the possibilities for the current item, then pass off the rest of the work by recursing on the remaining items. In this case you need to pass along a bit of extra information about what items not to use.
It works something like this:
def DistinctChooseFromEach(listOfChoicePairs, alreadyUsed = {}):
if listOfChoicePairs is empty: return []
for value in listOfChoicePairs[0]:
if value in alreadyUsed: continue;
newUsed = union(alreadyUsed, value)
remainingChoices = listOfChoicePairs[1:];
tails = DistinctChooseFromEach(remainingChoices, newUsed)
for tail in tails:
yield concat(value, tail)
Assume we need to list four numbers A, B, C, and D.
The sum of A+B+C+D is 10 and the value of each number is in the range of [0, 10].
Find all the possible combination.
The brute-force way is as follows:
for (int A = 0; A <=10; ++A)
for (int B = 0; B <=10-A; ++B)
{
if (A + B > 10) break;
for (int C = 0; C <=10-A-B; ++C)
{
if (A + B + C > 10) break;
for (int D = 0; D <=10-A-B-C; ++D)
{
if (A + B + C + D == 10)
{
cout << "A: " << A << ",B: " << B << ",C: " << C << ",D: " << D << endl;
break;
}
else if (A + B + C + D > 10)
break;
}
}
}
Q> Is there a better solution?
FYI: code is updated based on suggestion from #rici
You are asking for a method to enumerate the partitions of an integer. The linked wikipedia page lays out a few ways of doing that.
What about something like this:
void print4Partitions(int num) {
for (int A=1; A<num-3; A++) {
for (int B=A+1; B<num-A-2; B++) {
for (int C=B+1; C<num-(A+B)-1; C++) {
int D = num-A-B-C;
printf("%d %d %d %d\n", A, B, C, D);
}
}
}
}
The main ideas here are:
You really don't need to loop over the last number: it can be simply computed, as #nci mentions, as A, B, C, and the number to be partitions uniquely determine D.
You can limit your loops instead of testing and using break statements, which should result in faster code.
Given two lists of numbers and a list of totals (none in any particular order):
a = [1,2,3]
b = [4,5,6]
c = [6,7,8]
How can I find all sets of pairs d where d[k] = (a[i], b[j]) such that c[k] = a[i] + b[j] where pairs are used from a and b without replacement? (all lists can have duplicates)
d = [(1,5), (3,4), (2,6)]
d = [(2,4), (1,6), (3,5)]
For c = [7,7,7]:
d = [(1,6), (2,5), (3,4)]
(1 answer because all permutations are essentially equivalent)
I'd like to do this with lists of length ~500, so a naive matching/backtracking search is out of the question.
Okay, there is the brute force approach with pruning. This takes O(N^3)
For ease of demonstration, I will go through an N-by-N square that has the sum of a and b
S:
+ | 4 5 6
--|-------
1 | 5 6 7
2 | 6 7 8
3 | 7 8 9
And I am looking to build c={6,7,8}
I find a '6' in S. I remove it, and mark its row and column as unavailable
S:
+ | 4 5 6
--|-------
1 | / X /
2 | 6 / 8
3 | 7 / 9
Solution = { (1,5) }
Then I try to find a '7'
S:
+ | 4 5 6
--|-------
1 | / X /
2 | / / 8
3 | X / /
Solution = { (1,5) (3,4) }
And finally the '6'
S:
+ | 4 5 6
--|-------
1 | / X /
2 | / / X
3 | X / /
Solution = { (1,5) (3,4) (2,6) }
The 1st loop ( the one for '6' ) will continue and find another match : (2,4). This will then form the second solution { (2,4) (1,6) (3,5) }
Now, One way to improve this is, use some dynamic-programming: find out all possible combinations that give the result beforehand.
Given c={ 6 7 8}, create sets S_x where x is {6,7,8} and
S_x = { (i,j) } such that S[i][j]=x
So:
S_6 = { (1,2) (2,1) }
S_7 = { (1,3) (2,2) (3,1) }
S_8 = { (2,3) (3,2) }
And now, the same algorithm with given heuristics will run in O(S_l1 * S_l2 * ... S_lN), where S_li denotes the length of S_i.
This may run a factor faster in the average case.
It will also handle the c={7,7,7} case properly.
That's pretty much all I got.
Here is a brute-force approach in C++. It doesn't prune equivalent permutations e.g. for c=[7,7,7].
#include <vector>
#include <iostream>
#include <algorithm>
#include <utility>
using namespace std;
// numerical 3d match: x + y + z = b where
// x = a, y = b, z = -c, b = 0
template <typename T>
vector<pair<vector<T>, vector<T> > > n3dmatch(vector<T> a, vector<T> b, vector<T> c) {
vector<pair<vector<T>, vector<T> > > result;
if (a.size() != b.size() || b.size() != c.size()) return result;
vector<vector<T> > ap, bp;
sort(a.begin(), a.end());
sort(b.begin(), b.end());
do { ap.push_back(a); } while (next_permutation(a.begin(), a.end()));
do { bp.push_back(b); } while (next_permutation(b.begin(), b.end()));
for (int i = 0; i < ap.size(); i++) {
for (int j = 0; j < ap.size(); j++) {
bool match = true;
for (int k = 0; k < a.size(); k++) {
if ((ap[i][k] + bp[j][k]) != c[k]) {
match = false; break;
}
}
if (match) result.push_back({ ap[i], bp[j] });
}
}
return result;
}
int main(int argc, char *argv[]) {
vector<int> a = { 1, 2, 3 };
vector<int> b = { 4, 5, 6 };
vector<int> c = { 6, 7, 8 };
//vector<int> c = { 7, 7, 7 };
auto result = n3dmatch(a, b, c);
for (int i = 0; i < result.size(); i++) {
vector<int> &a = result[i].first;
vector<int> &b = result[i].second;
for (int j = 0; j < a.size(); j++) cout << a[j] << " "; cout << endl;
for (int j = 0; j < b.size(); j++) cout << b[j] << " "; cout << endl;
cout << "-" << endl;
}
return 0;
}