Kattis - Generalized Recursive Functions WA - algorithm

I have been desperately stuck on this question on Kattis here. The basic idea is that you are given a general formula for a valid two variable recursive function and then given that formula you are to evaluate the function of this function at various inputs. I have trawled through this question for over an hour and I was wondering if anyone could point me in the right direction (or give a counter-example) of why my answer is wrong. The code I used which got me a Wrong Answer verdict is shown below.
#include<bits/stdc++.h>
using namespace std;
long long dp[105][105];
int a[25];
int b[25];
long long rec(int x_in, int y_in, int coeffs, long long c) {
if(dp[x_in][y_in]!=-1){
return dp[x_in][y_in];
}
else {
long long ans = c;
for(int i=0; i<coeffs; ++i) {
int x_cell = max(0, x_in-a[i]);
int y_cell = max(0, y_in-b[i]);
ans+=rec(x_cell, y_cell, coeffs, c);
}
dp[x_in][y_in] = ans;
return dp[x_in][y_in];
}
}
int main() {
int n;
scanf("%d", &n);
string ex;
getline(cin, ex);
for(int caseno=0; caseno<n; ++caseno) {
memset(dp, -1, sizeof(dp));
if(caseno>0) printf("\n");
string coeffs_list;
getline(cin, coeffs_list);
int pairs = 0;
long long c, d;
char * dup = strdup(coeffs_list.c_str());
char * token = strtok(dup, " ") ;
while(token != NULL){
a[pairs] = atoi(token);
token = strtok(NULL, " ") ;
b[pairs] = atoi(token);
token = strtok(NULL, " ") ;
pairs++;
}
free(dup);
c= (long long) a[pairs-1];
d = (long long) b[pairs-1];
pairs--;
dp[0][0] = d;
for(int i=1; i<105; ++i) {dp[0][i] = d; dp[i][0]=d;}
string inputs;
getline(cin, inputs);
int x_i, y_i;
char * dup2 = strdup(inputs.c_str());
char * token2 = strtok(dup2, " ") ;
while(token2 != NULL){
x_i = atoi(token2);
token2 = strtok(NULL, " ") ;
y_i = atoi(token2);
token2 = strtok(NULL, " ") ;
printf("%lld\n", rec(x_i, y_i, pairs, c));
}
free(dup2);
}
}
As you can see the basic idea of what i did was to construct a dp table and evaluate the function accordingly. Thank you in advance for anyone that could help me over here.

The function can grow very fast, thus overflow a 64bit integer (you can check this by using assert(rec(...) >= 0) (not guaranteed but likely to fail for an overflow)). Use a custom BigInteger implementation or switch to Java/Python.
e.g. for n=20, a_i=1, b_i=0: f(x,y)=20*f(x-1,y)+c = O(20^x*(c+d))
This is also indicated by most solutions under stats using Java: https://open.kattis.com/problems/generalizedrecursivefunctions/statistics https://baylor.kattis.com/problems/generalizedrecursivefunctions/statistics

Related

What is causing error in first function which seemingly looks similar to second function?

Below functions are giving different results. What's the supposed difference between them that is causing different outputs. e.g n=30 and k=417219134 are giving output 0 and 1 respectively.
Function 1(Wrong):
int kthGrammar(int n, int k) {
if (n==1){
return 0;
}
int parent_node = kthGrammar(n-1, ceil(float(k)/2));
int isKodd = k%2;
if (isKodd){
return parent_node;}
else{
return parent_node==0?1:0;}
}
Function 2(Right):
int kthGrammar(int n, int k){
if (n==1){
return 0;
}
int isKodd = k%2;
if (isKodd){
return kthGrammar(n-1, (k+1)/2);}
else{
return (kthGrammar(n-1, k/2)==0?1:0);}
}
The int 417219134 can't be perfectly represented by a float.
float f = 417219134;
double d = 417219134;
std::cout << std::fixed
<< f << '\n' // 417219136.000000
<< d << '\n'; // 417219134.000000
This explains why ceil(float(k)/2) returns a number that is +1 off from the expected when k = 417219134.
I'd convert to double in the function instead:
int parent_node = kthGrammar(n-1, ceil(k / 2.));

Need to find highest non repeating number in custom vector

I'm creating a program, where you input n amount of mushroom pickers, they are in a shroom picking contest, they can find shroomA (worth 5 points), shroomB (worth 3 points) and shroomC (worth 15 points). I need to find the contest winner and print his/her name, but if two or more contestants have the same amount of points they are disqualified, meaning I need to find the highest non repeating result.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class ShroomPicker {
private:
string name;
long long int shroomA, shroomB, shroomC;
public:
void Input() {
char Name[100];
long long int shrooma, shroomb, shroomc;
cin >> Name >> shrooma >> shroomb >> shroomc;
name = Name;
shroomA = shrooma; shroomB = shroomb; shroomC = shroomc;
}
long long int calcPoints() {
return shroomA * 5 + shroomB * 3 + shroomC * 15;
}
string winnersName() {
return name;
}
};
int main() {
int n;
cin >> n;
vector<ShroomPicker> shr;
for (int i = 0; i < n; i++) {
ShroomPicker s;
s.Input();
shr.push_back(s);
}
long long int hiscore = 0;
int num = 0;
for (int i = 0; i < n; i++) {
long long int temp = 0;
temp = shr[i].calcPoints();
if (temp > hiscore) {
hiscore = temp;
num = i;
}
}
cout << shr[num].winnersName();
}
I made this program which finds the highest score even if repeats more than once, could someone suggest how I can find the highest non repeating score?
edit:
for (int i = 0; i < n; i++) {
long long int temp = 0;
temp = shr[i].calcPoints();
if (scoreMap.find(temp) == scoreMap.end()) {
scoreMap[temp] = Info{ i, false };
}
else {
scoreMap[temp] = Info{ i, true };
}
}
I would suggest sorting the list of participants in decreasing number of mushrooms picked (O[nlogn]) and then look through the list from start to finish (O[n] max). The first participant whose number of mushrooms picked is different than those of the adjacent participants (in the sorted list) is the winner.
The fastest (O(N)) way I can think of is to have:
struct Info
{
int picker_index;
bool disqualified;
}
// map from score to the Info object above
std::unordered_map<int, Info> scoreMap;
Iterate through pickers and update the map as follows:
-- If no item in the map, just add scoreMap[score] = Info {picker_index, false};
-- else, set disqualified = true on the existing item;
Once the map is constructed, find the max key in the map for which disqualified = false; similar to what you are doing now.

Trying TRIE DS implementation

So, I'tried implementing TRIE DS, and while the node in the tree gets the value of Words assigned after addWord ends, but when I traverse the tree, The value that prints is zero. What did I do wrong, unable to point out. Please can someone help.
#include<iostream>
#include<string>
using namespace std;
struct trie{
int words;
int prefixes;
trie* edges[26];
};
void addWord(trie* vertex, string word){
if(word.length() == 0){
vertex->words = vertex->words + 1;
}
else{
// cout<<word<<endl;
vertex->prefixes = vertex->prefixes + 1;
char k = word[0];
if(vertex->edges[k - 'a'] == NULL){
trie *n = (trie*)malloc(sizeof(trie));
n->words = 0;
n->prefixes = 0;
for(int i=0;i<26;i++)
vertex->edges[i] = NULL;
vertex->edges[k - 'a'] = n;
}
word.erase(0, 1);
addWord(vertex->edges[k - 'a'], word);
}
};
void traverse(trie *vertex){
if(vertex != NULL){
for(int i=0;i<26;i++){
if(vertex->edges[i] != NULL){
traverse(vertex->edges[i]);
cout<<char(i+'a')<<" - "<<vertex->prefixes<< " : "<<vertex->words<<endl;
}
}
}
};
int main(){
string word = "hello";
trie* head = (trie*)malloc(sizeof(trie));
for(int i=0;i<26;i++)
head->edges[i] = NULL;
head->words = 0;
head->prefixes = 0;
addWord(head, word);
string s = "lo";
traverse(head);
return 0;
}
There are two issues with code:
In your addWord function, inside else block, in the for loop, change vertex->edges[i] = NULL; to n->edges[i] = NULL;
The problem you asked for is in your traverse function. You are not printing the words count for node pointed by say last o, you are printing it for the node that have o as it's edge. So just change this:
cout<<char(i+'a')<<" - "<<vertex->prefixes<< " : "<<vertex->words<<endl;
to this:
cout<<char(i+'a')<<" - "<<vertex->edges[i]->prefixes<< " : "<<vertex->edges[i]->words<<endl;

Recursive algorithm to find all possible solutions in a nonogram row

I am trying to write a simple nonogram solver, in a kind of bruteforce way, but I am stuck on a relatively easy task. Let's say I have a row with clues [2,3] that has a length of 10
so the solutions are:
$$-$$$----
$$--$$$---
$$---$$$--
$$----$$$-
$$-----$$$
-$$----$$$
--$$---$$$
---$$--$$$
----$$-$$$
-$$---$$$-
--$$-$$$--
I want to find all the possible solutions for a row
I know that I have to consider each block separately, and each block will have an availible space of n-(sum of remaining blocks length + number of remaining blocks) but I do not know how to progress from here
Well, this question already have a good answer, so think of this one more as an advertisement of python's prowess.
def place(blocks,total):
if not blocks: return ["-"*total]
if blocks[0]>total: return []
starts = total-blocks[0] #starts = 2 means possible starting indexes are [0,1,2]
if len(blocks)==1: #this is special case
return [("-"*i+"$"*blocks[0]+"-"*(starts-i)) for i in range(starts+1)]
ans = []
for i in range(total-blocks[0]): #append current solutions
for sol in place(blocks[1:],starts-i-1): #with all possible other solutiona
ans.append("-"*i+"$"*blocks[0]+"-"+sol)
return ans
To test it:
for i in place([2,3,2],12):
print(i)
Which produces output like:
$$-$$$-$$---
$$-$$$--$$--
$$-$$$---$$-
$$-$$$----$$
$$--$$$-$$--
$$--$$$--$$-
$$--$$$---$$
$$---$$$-$$-
$$---$$$--$$
$$----$$$-$$
-$$-$$$-$$--
-$$-$$$--$$-
-$$-$$$---$$
-$$--$$$-$$-
-$$--$$$--$$
-$$---$$$-$$
--$$-$$$-$$-
--$$-$$$--$$
--$$--$$$-$$
---$$-$$$-$$
This is what i got:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef std::vector<bool> tRow;
void printRow(tRow row){
for (bool i : row){
std::cout << ((i) ? '$' : '-');
}
std::cout << std::endl;
}
int requiredCells(const std::vector<int> nums){
int sum = 0;
for (int i : nums){
sum += (i + 1); // The number + the at-least-one-cell gap at is right
}
return (sum == 0) ? 0 : sum - 1; // The right-most number don't need any gap
}
bool appendRow(tRow init, const std::vector<int> pendingNums, unsigned int rowSize, std::vector<tRow> &comb){
if (pendingNums.size() <= 0){
comb.push_back(init);
return false;
}
int cellsRequired = requiredCells(pendingNums);
if (cellsRequired > rowSize){
return false; // There are no combinations
}
tRow prefix;
int gapSize = 0;
std::vector<int> pNumsAux = pendingNums;
pNumsAux.erase(pNumsAux.begin());
unsigned int space = rowSize;
while ((gapSize + cellsRequired) <= rowSize){
space = rowSize;
space -= gapSize;
prefix.clear();
prefix = init;
for (int i = 0; i < gapSize; ++i){
prefix.push_back(false);
}
for (int i = 0; i < pendingNums[0]; ++i){
prefix.push_back(true);
space--;
}
if (space > 0){
prefix.push_back(false);
space--;
}
appendRow(prefix, pNumsAux, space, comb);
++gapSize;
}
return true;
}
std::vector<tRow> getCombinations(const std::vector<int> row, unsigned int rowSize) {
std::vector<tRow> comb;
tRow init;
appendRow(init, row, rowSize, comb);
return comb;
}
int main(){
std::vector<int> row = { 2, 3 };
auto ret = getCombinations(row, 10);
for (tRow r : ret){
while (r.size() < 10)
r.push_back(false);
printRow(r);
}
return 0;
}
And my output is:
$$-$$$----
$$--$$$---
$$---$$$--
$$----$$$--
$$-----$$$
-$$-$$$----
-$$--$$$--
-$$---$$$-
-$$----$$$-
--$$-$$$--
--$$--$$$-
--$$---$$$
---$$-$$$-
---$$--$$$
----$$-$$$
For sure, this must be absolutely improvable.
Note: i did't test it more than already written case
Hope it works for you

Parsing morse code

I am trying to solve this problem.
The goal is to determine the number of ways a morse string can be interpreted, given a dictionary of word.
What I did is that I first "translated" words from my dictionary into morse. Then, I used a naive algorithm, searching for all the ways it can be interpreted recursively.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <iterator>
using namespace std;
string morse_string;
int morse_string_size;
map<char, string> morse_table;
unsigned int sol;
void matches(int i, int factor, vector<string> &dictionary) {
int suffix_length = morse_string_size-i;
if (suffix_length <= 0) {
sol += factor;
return;
}
map<int, int> c;
for (vector<string>::iterator it = dictionary.begin() ; it != dictionary.end() ; it++) {
if (((*it).size() <= suffix_length) && (morse_string.substr(i, (*it).size()) == *it)) {
if (c.find((*it).size()) == c.end())
c[(*it).size()] = 0;
else
c[(*it).size()]++;
}
}
for (map<int, int>::iterator it = c.begin() ; it != c.end() ; it++) {
matches(i+it->first, factor*(it->second), dictionary);
}
}
string encode_morse(string s) {
string ret = "";
for (unsigned int i = 0 ; i < s.length() ; ++i) {
ret += morse_table[s[i]];
}
return ret;
}
int main() {
morse_table['A'] = ".-"; morse_table['B'] = "-..."; morse_table['C'] = "-.-."; morse_table['D'] = "-.."; morse_table['E'] = "."; morse_table['F'] = "..-."; morse_table['G'] = "--."; morse_table['H'] = "...."; morse_table['I'] = ".."; morse_table['J'] = ".---"; morse_table['K'] = "-.-"; morse_table['L'] = ".-.."; morse_table['M'] = "--"; morse_table['N'] = "-."; morse_table['O'] = "---"; morse_table['P'] = ".--."; morse_table['Q'] = "--.-"; morse_table['R'] = ".-."; morse_table['S'] = "..."; morse_table['T'] = "-"; morse_table['U'] = "..-"; morse_table['V'] = "...-"; morse_table['W'] = ".--"; morse_table['X'] = "-..-"; morse_table['Y'] = "-.--"; morse_table['Z'] = "--..";
int T, N;
string tmp;
vector<string> dictionary;
cin >> T;
while (T--) {
morse_string = "";
cin >> morse_string;
morse_string_size = morse_string.size();
cin >> N;
for (int j = 0 ; j < N ; j++) {
cin >> tmp;
dictionary.push_back(encode_morse(tmp));
}
sol = 0;
matches(0, 1, dictionary);
cout << sol;
if (T)
cout << endl << endl;
}
return 0;
}
Now the thing is that I only have 3 seconds of execution time allowed, and my algorithm won't work under this limit of time.
Is this the good way to do this and if so, what am I missing ? Otherwise, can you give some hints about what is a good strategy ?
EDIT :
There can be at most 10 000 words in the dictionary and at most 1000 characters in the morse string.
A solution that combines dynamic programming with a rolling hash should work for this problem.
Let's start with a simple dynamic programming solution. We allocate an vector which we will use to store known counts for prefixes of morse_string. We then iterate through morse_string and at each position we iterate through all words and we look back to see if they can fit into morse_string. If they can fit then we use the dynamic programming vector to determine how many ways we could have build the prefix of morse_string up to i-dictionaryWord.size()
vector<long>dp;
dp.push_back(1);
for (int i=0;i<morse_string.size();i++) {
long count = 0;
for (int j=1;j<dictionary.size();j++) {
if (dictionary[j].size() > i) continue;
if (dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)) {
count += dp[i-dictionary[j].size()];
}
}
dp.push_back(count);
}
result = dp[morse_code.size()]
The problem with this solution is that it is too slow. Let's say that N is the length of morse_string and M is the size of the dictionary and K is the size of the largest word in the dictionary. It will do O(N*M*K) operations. If we assume K=1000 this is about 10^10 operations which is too slow on most machines.
The K cost came from the line dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)
If we could speed up this string matching to constant or log complexity we would be okay. This is where rolling hashing comes in. If you build a rolling hash array of morse_string then the idea is that you can compute the hash of any substring of morse_string in O(1). So you could then do hash(dictionary[j]) == hash(morse_string.substring(i-dictionary[j].size(),i))
This is good but in the presence of imperfect hashing you could have multiple words from the dictionary with the same hash. That would mean that after getting a hash match you would still need to match the strings as well as the hashes. In programming contests, people often assume perfect hashing and skip the string matching. This is often a safe bet especially on a small dictionary. In case it doesn't produce a perfect hashing (which you can check in code) you can always adjust your hash function slightly and maybe the adjusted hash function will produce a perfect hashing.

Resources