DP Approach ? Output should be the max sum. interview ( still have not idea, any hints) at at well known company - dynamic-programming

You have a table and in each cell there is either a positive integer or the cell is blocked. You have a player starting from bottom left and want to get to the top right in such a way that you maximize the sum of integers on your way. You are only allowed to move up or right but not through blocked cells. Output should be the max sum.

On my code I am making the assumption that the answer will fit on a long long type.
I am also assuming that is a square matrix for simplicity, but you can adapt the algorithm for any rectangular matrix with almost no effort.
If the input matrix is N x N, the complexity of this approach is O(N ^ 2).
#include <vector>
#include <iostream>
#include <algorithm>
constexpr int maxDimension = 100;
using namespace std;
long long matrix[maxDimension][maxDimension];
long long dp[maxDimension][maxDimension];
int main()
{
// I am assuming that the matrix is filled with positive
// integers, and the blocked cell's are filled with -1.
// reading the values for the matrix
for(int i = 0; i < maxDimension; ++i)
{
for(int j = 0; j < maxDimension; ++j)
{
cin >> matrix[i][j];
}
}
/*
For every pair(i, j),
dp[i][j] is the maximum
sum we can achive going from
(0,0) to (i, j)
*/
// Observation if dp[i][j] is equal to -1, it is because we cannot reach the cell (i, j) because of blocked cells
dp[0][0] = matrix[0][0];
// this calculates the dp for row == 0
for(int col = 1; col < maxDimension; ++col)
{
if(dp[0][col - 1] != -1 && matrix[0][col] != -1)
{
dp[0][col] = dp[0][col-1] + matrix[0][col];
}
else dp[0][col] = -1;
}
// now I will calculate the dp for column == 0
for(int row = 1; row < maxDimension; ++row)
{
if(dp[row - 1][0] != -1 && matrix[row][0] != -1)
{
dp[row][0] = dp[row-1][0] + matrix[row][0];
}
else dp[row][0] = -1;
}
// Now that I have calculated the base cases, I will calculate the dp for the other states
// I will use the following expression
/* dp[i][j] = if (matrix[i][j] == -1) -> -1
else if (dp[i-1][j] != -1 or dp[i][j-1] != -1) -> max(dp[i-1][j], dp[i][j - 1]) + matrix[i][j]
else -> -1
*/
for(int row = 1; row < maxDimension; ++row)
{
for(int col = 1; col < maxDimension; ++col)
{
if(matrix[i][j] != -1 && ( dp[i-1][j] != -1 || dp[i][j-1] != -1) )
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + matrix[i][j];
}
else dp[i][j] = -1;
}
}
if(dp[maxDimension-1][maxDimension-1] == -1) cout << "The top right cell is not reachable from the bottom left cell" << endl;
else cout << "The best sum possible is " << dp[maxDimension - 1][maxDimension - 1] << endl;
return 0;
}

Related

CS50 pset 1 - Credit, more comfortable

I have the following errors
:( identifies 5105105105105100 as MASTERCARD
expected "MASTERCARD\n", not "INVALID\n"
:( identifies 4111111111111111 as VISA
expected "VISA\n", not "INVALID\n"
:( identifies 4012888888881881 as VISA
expected "VISA\n", not "INVALID\n"
but for the card to be correct the last digit should be which is correct in my case. Please help
------------------- CODE -----------------------
#include <cs50.h>
#include <stdio.h>
int main()
{
long long cardNumber;
// get a card number from the user
do
{
printf("Your card number please: ");
//scanf("%lld", &cardNumber);
cardNumber = get_long_long();
}
while (cardNumber < 0);
//check the length of the card
int counter = 0;
long long cardNumberNeo = cardNumber;
while (cardNumberNeo > 0)
{
cardNumberNeo = cardNumberNeo / 10;
counter++;
}
if (counter != 15 && counter != 16 && counter != 13)
{
printf("INVALID\n");
}
// Array of card number
cardNumberNeo = cardNumber;
int cardNumberArr[counter], cardNumberArrNeo[counter], i;
for (i=0; i<counter; i++)
{
cardNumberArr[counter-i-1] = cardNumberNeo % 10;
cardNumberArrNeo[counter-i-1] = cardNumberArr[counter-i-1];
cardNumberNeo = cardNumberNeo / 10;
}
for (int i = 1; i < counter; i+=2)
{
cardNumberArrNeo[i] = cardNumberArrNeo[i] * 2;
}
int oddNumber = 0;
int temp;
for (int i = 0; i < counter; i++)
{
temp = (cardNumberArrNeo[i] % 10) + (cardNumberArrNeo[i]/10 % 10);
oddNumber = oddNumber + temp;
}
if (oddNumber % 10 == 0)
{
// Check the type of the card
if ( ((cardNumberArr[0] == 3 && cardNumberArr[1] == 4) || (cardNumberArr[0] == 3 && cardNumberArr[1] == 7)) && counter == 15 )
{
printf("AMEX\n");
}
else if (cardNumberArr[0] == 5 && cardNumberArr[1] >= 1 && cardNumberArr[1] <= 5 && counter == 16)
{
printf("MASTERCARD\n");
}
else if (cardNumberArr[0] == 4 && (counter == 13 || counter == 16 ))
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
}
else
{
printf("INVALID\n");
}
return 0;
}
This will work.....as long as the credit card number has an odd length. Remember, Luhn's algorithm rule [emphasis added]:
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products' digits together.
This loop for (int i = 1; i < counter; i+=2) processes the wrong digits for a card with even length. Such numbers need to start at the 0th index in order to end up at the correct place (ie penultimate digit).

Connect 4 - C++: Unable to get program to determine whether a win has occurred diagonally

/* The program for the connect 4 gameboard currently follows as the code beneath. The source code represents the initial player as an odd number that is increased by 1, following the second player's move, which is noted under an even number. I am not certain on the manner to get it to detect a win when there are four consecutive odd or even numbers in a diagonal direction. The issue may stem to the use of "if (iswin())" and "winflag = true" in that winflag is never deemed true, however, am not certain.
*/
#include <iostream>
using namespace std;
/*global constants and variables;
*/
const int H = 6;
const int W = 7;
int height = H;
int width = W;
int colstatus[W]; // 1-D keeps tracking which row will be next available spot for each col.
int board[H][W]; // 2-D array
int steps = 0;
int lastcol;
bool winflag = false;
int neighbourrowpos;
int neighbourcolpos;
// function prototypes
int whichside(int, int);
void initialize();
bool islegal(int, int);
bool play();
bool iswin();
void showgame();
int main();
// implementation of functions
bool islegal(int row, int col)
{
if (row<0 || row >= H || col<0 || col>W) return false; // out of boundary of the board.
else
return true;
}
int whichside(int row, int col)
{
if (board[row][col] == 0) return 0; // means a spot is open
if (board[row][col] % 2) return 1; // means odd side
else return -1; // means even side
}
bool iswin()
{
int counter = 1;
int lastrow;
lastrow = colstatus[lastcol] + 1; // based on the next available one to determine the row of the last move.
// vertically, the board should be checked solely in a downward direction, not upward
neighbourrowpos = lastrow + 1; // the first one right after the last move.
neighbourcolpos = lastcol;
while (islegal(neighbourrowpos, neighbourcolpos))
{
//if the stone at nextposition is on the same side of the last drop.
if (whichside(neighbourrowpos, neighbourcolpos) == whichside(colstatus[lastcol] + 1, lastcol))
{
counter++;
if (counter == 4) return true; // win
else
neighbourrowpos++; // ++ to go down
}
else
return false; // no win occurs due to the encounter of of another side before reaching 4.
}
// check horizontally, both left and right
counter = 1; // resets counter to 1 from the last move to check horizontal
//check left first.
neighbourrowpos = lastrow;
neighbourcolpos = lastcol - 1;
while (islegal(neighbourrowpos, neighbourcolpos))
{
if (whichside(neighbourrowpos, neighbourcolpos) == whichside(lastrow, lastcol))
{
counter++;
if (counter == 4) return true; // win
else
neighbourcolpos--; //-- to go left
}
else
break; // too early to return false because the right side may contribute too. The loop should have a break so as to permit the user to continue testing on the right side.
}
// the program will continue to perform a check on the right wing from the previous move.
neighbourcolpos = lastcol + 1;
while (islegal(neighbourrowpos, neighbourcolpos))
{
if (whichside(neighbourrowpos, neighbourcolpos) == whichside(lastrow, lastcol))
{
counter++;
if (counter == 4) return true; // win
else
neighbourcolpos++; //++ to go right
}
else
return false; // when the program has been checked on its left and right sides and meet a different side before reaching 4, which signifies that it can return.
}
//in this stance, the program should check diagonally topleft to bottomright. once more, ensure that two segments are symmetric with respect to the previous move.
neighbourrowpos = lastcol;
neighbourcolpos = lastrow - 1;
while (islegal(neighbourrowpos, neighbourcolpos))
{
if (whichside(neighbourrowpos, neighbourcolpos) == whichside(lastrow, lastcol))
{
counter++;
if (counter == 4) return true; //win
else
neighbourcolpos--; //-- to shift to the left
}
else
return false;
}
neighbourcolpos = lastrow + 1;
while (islegal(neighbourrowpos, neighbourcolpos))
{
if (whichside(neighbourrowpos, neighbourcolpos) == whichside(lastrow, lastcol))
{
counter++;
if (counter == 4) return true; // winner
else
neighbourcolpos++; //++ to shift to the right
}
else return false;
}
counter = 1;
neighbourrowpos = lastrow - 1;
neighbourcolpos = lastcol - 1;
neighbourrowpos = lastrow + 1;
neighbourcolpos = lastcol + 1;
//check diagonally top-right to bottomleft
counter = 1;
neighbourrowpos = lastrow + 1; //conducts a check on the lower left portion of the board
neighbourcolpos = lastcol - 1;
neighbourrowpos = lastrow - 1; //performs a check on the upper right segment of the board
neighbourcolpos = lastcol + 1;
return false;
}
bool play()
{
cout << "Input column number (0-6): ";
cin >> lastcol;
if (lastcol<0 || lastcol >= W) return false;
if (colstatus[lastcol] > -1)
{
board[colstatus[lastcol]][lastcol] = ++steps; // increase step by 1 to maintain counter of the amount of moves. Step has been initialized at zero.
colstatus[lastcol]--;
showgame();
if (iswin()) //This may be the issue, however, am not certain
winflag = true;
return true;
}
else
{
return false;
}
}
void initialize()
{
for (int col = 0; col<W; col++)
colstatus[col] = H - 1;
for (int row = 0; row<H; row++)
for (int col = 0; col<W; col++)
board[row][col] = 0;
}
void showgame()
{
for (int row = 0; row < H; row++)
{
for (int col = 0; col < W; col++)
cout << board[row][col] << "\t";
cout << endl;
}
cout << "---------------------------------------------" << endl;
for (int col = 0; col<W; col++)
cout << colstatus[col] << "\t";
cout << endl;
}
int main()
{
initialize();
showgame();
do
{
do {
bool f = play(); // call play until it is true;
if (f == false)
cout << "You pick a wrong column. Please try again";
else
break; // if it is a legal move, check winflag
} while (true);
if (winflag == true)
{
cout << whichside(colstatus[lastcol] + 1, lastcol) << " win!" << endl; // -1 even side, 1 odd side
break;
}
else
{
// something must be included here but am not certain on the specific statement
}
} while (true);
return 0;
}
This is just a general suggestion to how to check for wins in connect four. Consider that there are 4 ways to win: Horizontal, Vertical, Left Diagonal, and Right Diagonal. You could iterate over the entire board and at each cell that contains a game piece you could do a breadth first search. This would actually need to be 4 versions of the search, one for each way to win. Another constraint that is common to all of the searches: only consider cells that contain the same type of game piece. When searching keep track of the number of steps traveled. Once you have successfully traveled 4 steps, there is a win. This also assumes that you will use some data structure for cycle detection.
With that said the Diagonal versions of the search would only consider cells on their immediate respective corners. For instance the Left Diagonal search with a starting cell of (2,1) would consider the following:[(1, 2), (3, 0)], assuming that (0, 0) is the top left corner of the board.

Dynamic Programming, choosing the highest total value

The Data:
A list of integers increasing in order (0,1,2,3,4,5.......)
A list of values that belong to those integers. As an example, 0 = 33, 1 = 45, 2 = 21, ....etc.
And an incrementing variable x which represent a minimum jump value.
x is the value of each jump. For example if x = 2, if 1 is chosen you cannot choose 2.
I need to determine the best way to choose integers, given some (x), that produce the highest total value from the value list.
EXAMPLE:
A = a set of 1 foot intervals (0,1,2,3,4,5,6,7,8,9)
B = the amount of money at each interval (9,5,7,3,2,7,8,10,21,12)
Distance = the minimum distance you can cover
- i.e. if the minimum distance is 3, you must skip 2 feet and leave the money, then you can
pick up the amount at the 3rd interval.
if you pick up at 0, the next one you can pick up is 3, if you choose 3 you can
next pick up 6 (after skipping 4 and 5). BUT, you dont have to pick up 6, you
could pick up 7 if it is worth more. You just can't pick up early.
So, how can I programmatically make the best jumps and end with the most money at the end?
So I am using the below equation for computing the opt value in the dynamic programming:
Here d is distance.
if (i -d) >= 0
opt(i) = max (opt(i-1), B[i] + OPT(i-d));
else
opt(i) = max (opt(i-1), B[i]);
Psuedo-code for computing the OPT value:
int A[] = {integers list}; // This is redundant if the integers are consecutive and are always from 0..n.
int B[] = {values list};
int i = 0;
int d = distance; // minimum distance between two picks.
int numIntegers = sizeof(A)/sizeof(int);
int opt[numIntegers];
opt[0] = B[0]; // For the first one Optimal value is picking itself.
for (i=1; i < numIntegers; i++) {
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[i]);
} else {
opt[i] = max (opt[i-1], B[i] + opt[i-d]);
}
}
EDIT based on OP's requirement about getting the selected integers from B:
for (i=numIntegres - 1; i >= 0;) {
if ((i == 0) && (opt[i] > 0)) {
printf ("%d ", i);
break;
}
if (opt[i] > opt[i-1]) {
printf ("%d ", i);
i = i -d;
} else {
i = i - 1;
}
}
If A[] does not have consecutive integers from 0 to n.
int A[] = {integers list}; // Here the integers may not be consecutive
int B[] = {values list};
int i = 0, j = 0;
int d = distance; // minimum distance between two picks.
int numAs = sizeof(A)/sizeof(int);
int numIntegers = A[numAs-1]
int opt[numIntegers];
opt[0] = 0;
if (A[0] == 0) {
opt[0] = B[0]; // For the first one Optimal value is picking itself.
j = 1;
}
for (i=1; i < numIntegers && j < numAs; i++, j++) {
if (i < A[j]) {
while (i < A[j]) {
opt[i] = opt[i -1];
i = i + 1:
}
}
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[j]);
} else {
opt[i] = max (opt[i-1], B[j] + opt[i-d]);
}
}

Finding the ranking of a word (permutations) with duplicate letters

I'm posting this although much has already been posted about this question. I didn't want to post as an answer since it's not working. The answer to this post (Finding the rank of the Given string in list of all possible permutations with Duplicates) did not work for me.
So I tried this (which is a compilation of code I've plagiarized and my attempt to deal with repetitions). The non-repeating cases work fine. BOOKKEEPER generates 83863, not the desired 10743.
(The factorial function and letter counter array 'repeats' are working correctly. I didn't post to save space.)
while (pointer != length)
{
if (sortedWordChars[pointer] != wordArray[pointer])
{
// Swap the current character with the one after that
char temp = sortedWordChars[pointer];
sortedWordChars[pointer] = sortedWordChars[next];
sortedWordChars[next] = temp;
next++;
//For each position check how many characters left have duplicates,
//and use the logic that if you need to permute n things and if 'a' things
//are similar the number of permutations is n!/a!
int ct = repeats[(sortedWordChars[pointer]-64)];
// Increment the rank
if (ct>1) { //repeats?
System.out.println("repeating " + (sortedWordChars[pointer]-64));
//In case of repetition of any character use: (n-1)!/(times)!
//e.g. if there is 1 character which is repeating twice,
//x* (n-1)!/2!
int dividend = getFactorialIter(length - pointer - 1);
int divisor = getFactorialIter(ct);
int quo = dividend/divisor;
rank += quo;
} else {
rank += getFactorialIter(length - pointer - 1);
}
} else
{
pointer++;
next = pointer + 1;
}
}
Note: this answer is for 1-based rankings, as specified implicitly by example. Here's some Python that works at least for the two examples provided. The key fact is that suffixperms * ctr[y] // ctr[x] is the number of permutations whose first letter is y of the length-(i + 1) suffix of perm.
from collections import Counter
def rankperm(perm):
rank = 1
suffixperms = 1
ctr = Counter()
for i in range(len(perm)):
x = perm[((len(perm) - 1) - i)]
ctr[x] += 1
for y in ctr:
if (y < x):
rank += ((suffixperms * ctr[y]) // ctr[x])
suffixperms = ((suffixperms * (i + 1)) // ctr[x])
return rank
print(rankperm('QUESTION'))
print(rankperm('BOOKKEEPER'))
Java version:
public static long rankPerm(String perm) {
long rank = 1;
long suffixPermCount = 1;
java.util.Map<Character, Integer> charCounts =
new java.util.HashMap<Character, Integer>();
for (int i = perm.length() - 1; i > -1; i--) {
char x = perm.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
for (java.util.Map.Entry<Character, Integer> e : charCounts.entrySet()) {
if (e.getKey() < x) {
rank += suffixPermCount * e.getValue() / xCount;
}
}
suffixPermCount *= perm.length() - i;
suffixPermCount /= xCount;
}
return rank;
}
Unranking permutations:
from collections import Counter
def unrankperm(letters, rank):
ctr = Counter()
permcount = 1
for i in range(len(letters)):
x = letters[i]
ctr[x] += 1
permcount = (permcount * (i + 1)) // ctr[x]
# ctr is the histogram of letters
# permcount is the number of distinct perms of letters
perm = []
for i in range(len(letters)):
for x in sorted(ctr.keys()):
# suffixcount is the number of distinct perms that begin with x
suffixcount = permcount * ctr[x] // (len(letters) - i)
if rank <= suffixcount:
perm.append(x)
permcount = suffixcount
ctr[x] -= 1
if ctr[x] == 0:
del ctr[x]
break
rank -= suffixcount
return ''.join(perm)
If we use mathematics, the complexity will come down and will be able to find rank quicker. This will be particularly helpful for large strings.
(more details can be found here)
Suggest to programmatically define the approach shown here (screenshot attached below) given below)
I would say David post (the accepted answer) is super cool. However, I would like to improve it further for speed. The inner loop is trying to find inverse order pairs, and for each such inverse order, it tries to contribute to the increment of rank. If we use an ordered map structure (binary search tree or BST) in that place, we can simply do an inorder traversal from the first node (left-bottom) until it reaches the current character in the BST, rather than traversal for the whole map(BST). In C++, std::map is a perfect one for BST implementation. The following code reduces the necessary iterations in loop and removes the if check.
long long rankofword(string s)
{
long long rank = 1;
long long suffixPermCount = 1;
map<char, int> m;
int size = s.size();
for (int i = size - 1; i > -1; i--)
{
char x = s[i];
m[x]++;
for (auto it = m.begin(); it != m.find(x); it++)
rank += suffixPermCount * it->second / m[x];
suffixPermCount *= (size - i);
suffixPermCount /= m[x];
}
return rank;
}
#Dvaid Einstat, this was really helpful. It took me a WHILE to figure out what you were doing as I am still learning my first language(C#). I translated it into C# and figured that I'd give that solution as well since this listing helped me so much!
Thanks!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace CsharpVersion
{
class Program
{
//Takes in the word and checks to make sure that the word
//is between 1 and 25 charaters inclusive and only
//letters are used
static string readWord(string prompt, int high)
{
Regex rgx = new Regex("^[a-zA-Z]+$");
string word;
string result;
do
{
Console.WriteLine(prompt);
word = Console.ReadLine();
} while (word == "" | word.Length > high | rgx.IsMatch(word) == false);
result = word.ToUpper();
return result;
}
//Creates a sorted dictionary containing distinct letters
//initialized with 0 frequency
static SortedDictionary<char,int> Counter(string word)
{
char[] wordArray = word.ToCharArray();
int len = word.Length;
SortedDictionary<char,int> count = new SortedDictionary<char,int>();
foreach(char c in word)
{
if(count.ContainsKey(c))
{
}
else
{
count.Add(c, 0);
}
}
return count;
}
//Creates a factorial function
static int Factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * Factorial(n - 1);
}
}
//Ranks the word input if there are no repeated charaters
//in the word
static Int64 rankWord(char[] wordArray)
{
int n = wordArray.Length;
Int64 rank = 1;
//loops through the array of letters
for (int i = 0; i < n-1; i++)
{
int x=0;
//loops all letters after i and compares them for factorial calculation
for (int j = i+1; j<n ; j++)
{
if (wordArray[i] > wordArray[j])
{
x++;
}
}
rank = rank + x * (Factorial(n - i - 1));
}
return rank;
}
//Ranks the word input if there are repeated charaters
//in the word
static Int64 rankPerm(String word)
{
Int64 rank = 1;
Int64 suffixPermCount = 1;
SortedDictionary<char, int> counter = Counter(word);
for (int i = word.Length - 1; i > -1; i--)
{
char x = Convert.ToChar(word.Substring(i,1));
int xCount;
if(counter[x] != 0)
{
xCount = counter[x] + 1;
}
else
{
xCount = 1;
}
counter[x] = xCount;
foreach (KeyValuePair<char,int> e in counter)
{
if (e.Key < x)
{
rank += suffixPermCount * e.Value / xCount;
}
}
suffixPermCount *= word.Length - i;
suffixPermCount /= xCount;
}
return rank;
}
static void Main(string[] args)
{
Console.WriteLine("Type Exit to end the program.");
string prompt = "Please enter a word using only letters:";
const int MAX_VALUE = 25;
Int64 rank = new Int64();
string theWord;
do
{
theWord = readWord(prompt, MAX_VALUE);
char[] wordLetters = theWord.ToCharArray();
Array.Sort(wordLetters);
bool duplicate = false;
for(int i = 0; i< theWord.Length - 1; i++)
{
if(wordLetters[i] < wordLetters[i+1])
{
duplicate = true;
}
}
if(duplicate)
{
SortedDictionary<char, int> counter = Counter(theWord);
rank = rankPerm(theWord);
Console.WriteLine("\n" + theWord + " = " + rank);
}
else
{
char[] letters = theWord.ToCharArray();
rank = rankWord(letters);
Console.WriteLine("\n" + theWord + " = " + rank);
}
} while (theWord != "EXIT");
Console.WriteLine("\nPress enter to escape..");
Console.Read();
}
}
}
If there are k distinct characters, the i^th character repeated n_i times, then the total number of permutations is given by
(n_1 + n_2 + ..+ n_k)!
------------------------------------------------
n_1! n_2! ... n_k!
which is the multinomial coefficient.
Now we can use this to compute the rank of a given permutation as follows:
Consider the first character(leftmost). say it was the r^th one in the sorted order of characters.
Now if you replace the first character by any of the 1,2,3,..,(r-1)^th character and consider all possible permutations, each of these permutations will precede the given permutation. The total number can be computed using the above formula.
Once you compute the number for the first character, fix the first character, and repeat the same with the second character and so on.
Here's the C++ implementation to your question
#include<iostream>
using namespace std;
int fact(int f) {
if (f == 0) return 1;
if (f <= 2) return f;
return (f * fact(f - 1));
}
int solve(string s,int n) {
int ans = 1;
int arr[26] = {0};
int len = n - 1;
for (int i = 0; i < n; i++) {
s[i] = toupper(s[i]);
arr[s[i] - 'A']++;
}
for(int i = 0; i < n; i++) {
int temp = 0;
int x = 1;
char c = s[i];
for(int j = 0; j < c - 'A'; j++) temp += arr[j];
for (int j = 0; j < 26; j++) x = (x * fact(arr[j]));
arr[c - 'A']--;
ans = ans + (temp * ((fact(len)) / x));
len--;
}
return ans;
}
int main() {
int i,n;
string s;
cin>>s;
n=s.size();
cout << solve(s,n);
return 0;
}
Java version of unrank for a String:
public static String unrankperm(String letters, int rank) {
Map<Character, Integer> charCounts = new java.util.HashMap<>();
int permcount = 1;
for(int i = 0; i < letters.length(); i++) {
char x = letters.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
permcount = (permcount * (i + 1)) / xCount;
}
// charCounts is the histogram of letters
// permcount is the number of distinct perms of letters
StringBuilder perm = new StringBuilder();
for(int i = 0; i < letters.length(); i++) {
List<Character> sorted = new ArrayList<>(charCounts.keySet());
Collections.sort(sorted);
for(Character x : sorted) {
// suffixcount is the number of distinct perms that begin with x
Integer frequency = charCounts.get(x);
int suffixcount = permcount * frequency / (letters.length() - i);
if (rank <= suffixcount) {
perm.append(x);
permcount = suffixcount;
if(frequency == 1) {
charCounts.remove(x);
} else {
charCounts.put(x, frequency - 1);
}
break;
}
rank -= suffixcount;
}
}
return perm.toString();
}
See also n-th-permutation-algorithm-for-use-in-brute-force-bin-packaging-parallelization.

Conways's Game of life array problems

I'm writing a Conway's life game for school. In the program I am having trouble with the arrays taking the values I am assigning them. At one point in the program they print out the value assigned to them (1) yet at the end of the program when I need to print the array to show the iterations of the game it shows an incredibly low number. The other trouble was I was encountering difficulties when putting in a loop that would ask if it wants you to run another iteration. So I removed it until the previous errors were fixed.
Im writing this with C++
#include <stdio.h>
int main (void)
{
int currentarray [12][12];
int futurearray [12][12];
char c;
char check = 'y';
int neighbors = 0;
int x = 0; // row
int y = 0; //column
printf("Birth an organism will be born in each empty location that has exactly three neighbors.\n");
printf("Death an organism with four or more organisms as neighbors will die from overcrowding.\n");
printf("An organism with fewer than two neighbors will die from loneliness.\n");
printf("Survival an organism with two or three neighbors will survive to the next generation.\n");
printf( "To create life input x, y coordinates.\n");
while ( check == 'y' )
{
printf("Enter x coordinate.\n");
scanf("%d", &x ); while((c = getchar()) != '\n' && c != EOF);
printf("Enter y coordinate.\n");
scanf("%d", &y ); while((c = getchar()) != '\n' && c != EOF);
currentarray [x][y] = 1;
printf ("%d\n", currentarray[x][y]);
printf( "Do you wish to enter more input? y/n.\n");
scanf("%c", &check); while((c = getchar()) != '\n' && c != EOF);
}
// Note - Need to add a printf statement showing the array before changes are made after input added.
// check for neighbors
while(check == 'y')
{
for(y = 0; y <= 12; y++)
{
for(x = 0; x <= 12; x++)
{
//Begin counting number of neighbors:
if(currentarray[x-1][y-1] == 1) neighbors += 1;
if(currentarray[x-1][y] == 1) neighbors += 1;
if(currentarray[x-1][y+1] == 1) neighbors += 1;
if(currentarray[x][y-1] == 1) neighbors += 1;
if(currentarray[x][y+1] == 1) neighbors += 1;
if(currentarray[x+1][y-1] == 1) neighbors += 1;
if(currentarray[x+1][y] == 1) neighbors += 1;
if(currentarray[x+1][y+1] == 1) neighbors += 1;
//Apply rules to the cell:
if(currentarray[x][y] == 1 && neighbors < 2)
futurearray[x][y] = 0;
else if(currentarray[x][y] == 1 && neighbors > 3)
futurearray[x][y] = 0;
else if(currentarray[x][y] == 1 && (neighbors == 2 || neighbors == 3))
futurearray[x][y] = 1;
else if(currentarray[x][y] == 0 && neighbors == 3)
futurearray[x][y] = 1;
}
}
}
// Set the current array to the future and change the future to 0
{
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//Begin the process
currentarray [x][y] = futurearray [x][y];
futurearray [x][y] = 0;
}
}
}
{
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//print the current life board
printf("%d ", currentarray[x][y]);
}
}
}
// Have gone through one iteration of Life
//Ask to do another iteration
printf("Do you wish to continue y/n?\n");
scanf("%c", &check); while((c = getchar()) != '\n' && c != EOF);
return 0;
}
You are defining your arrays as [12][12].
In your generation loop you walk from i = 0 to i <= 12, which is 13 steps instead of the 12 of the array. Additionally you are trying to access x-1 and y-1, which can be as low as -1. Again not inside your array.
Sometimes you get semi-useful values from within your array, but on some borders you are just accessing random data.
Try to correct your border.
You forgot to set neighbors to 0 before counting them.
Since this is C++ (not C), you might as well declare neighbors inside the loop body. Makes these kinds of issues easier to spot, too.
Also, is it me, or is that while loop never going to finish? Your braces are a mess, in general, as is your indentation. You could do yourself and us a favour by cleaning those up.
Obviously agree with all the above suggestions. One nice trick you might want to implement with Life is to create an extra border around your area. So if the user wants a 12x12 grid (and you should allow width/height to be specified and allocate memory dynamically) internally you hold a 14x14 grid corresponding to a border around the actual grid. Before running the calculation copy the top row to the bottom border, bottom row to the top border etc. Now you can run the main algorithm on the inner 12x12 grid without worrying about edge cases. This will enable your patterns to re-appear on the other side if they fall off the edge.
You're also forgetting to set the values of both arrays to zero. This will take care of the ridiculous number issue you're having. you can do that by copying this for loop:
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//Begin the process
currentarray [x][y] = futurearray [x][y];
futurearray [x][y] = 0;
}
}
and pasting it before the while loop but instead of setting currentarray[x][y] = futurearray[x][y], set it to 0. Also, if the coordinates are viewable locations instead of array co-ordinates, you'll want to change this:
printf ("%d\n", currentarray[x][y]);
to this:
printf ("%d\n", currentarray[x-1][y-1]);
I would also recommend putting a printf with a newline (\n) after each row has been printed and a tab (\t) after each item so that the formatting looks cleaner.

Resources