Matrix determinant algorithm C++ - c++

I'm new to programming and I was looking for a way to find the determinant of a matrix. I found this code online, but I have trouble understanding the algorithm in place here. I have no problems for the base of the recursion , but the continue and main loop I have trouble understanding. Big thanks to anyone who can explain to me the algorithm.
int determ(int a[MAX][MAX],int n) {
int det=0, p, h, k, i, j, temp[MAX][MAX];
if(n==1) {
return a[0][0];
} else if(n==2) {
det=(a[0][0]*a[1][1]-a[0][1]*a[1][0]);
return det;
} else {
for(p=0;p<n;p++) {
h = 0;
k = 0;
for(i=1;i<n;i++) {
for( j=0;j<n;j++) {
if(j==p) {
continue;
}
temp[h][k] = a[i][j];
k++;
if(k==n-1) {
h++;
k = 0;
}
}
}
det=det+a[0][p]*pow(-1,p)*determ(temp,n-1);
}
return det;
}
}

This algorithm uses a divide-conquer approach for solving the problem (finding the determinant of an N*N Matrix).
The algorithm uses a recursive pattern which is one of divide and conquer approaches. You can find out this by noticing the algorithm is calling itself in the third condition statement.
Every recursive algorithm have an exit condition which is the first if-statement in your code. and they also contain a section which is the solution to the most convenient problem or an atomic problem of the main big problem which is hard to solve in the first place. The atomic problem or the most-divided problem can be solved easily as you can see the the second if-statement of your code. In your case it is actually solving the determinant of a 2*2 Matrix.
The most important part of your code to understand which is challenging a little bit too is the part you do the dividing (which is recursive too!).
This part has the key to conquering either. By doing a little back trace and numerical examples you can find it out:
det = det + a[0][p] * pow(-1,p) * determ(temp,n-1);
For the final suggestion try a 3*3 Matrix which only needs one dividing.
Good luck with that.
This book is a great one to start studying and understanding algorithms

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int **submatrix(int **matrix, unsigned int n, unsigned int x, unsigned int y) {
int **submatrix = new int *[n - 1];
int subi = 0;
for (int i = 0; i < n; i++) {
submatrix[subi] = new int[n - 1];
int subj = 0;
if (i == y) {
continue;
}
for (int j = 0; j < n; j++) {
if (j == x) {
continue;
}
submatrix[subi][subj] = matrix[i][j];
subj++;
}
subi++;
}
return submatrix;
}
int determinant(int **matrix, unsigned int n) {
int det = 0;
if (n == 2) {
return matrix[0][0] * matrix[1][1] - matrix[1][0] * matrix[0][1];
}
for (int x = 0; x < n; ++x) {
det += ((x % 2 == 0 ? 1 : -1) * matrix[0][x] * determinant(submatrix(matrix, n, x, 0), n - 1));
}
return det;
}
int main() {
int n;
cin >> n;
int **matrix = new int *[n];
for (int i = 0; i < n; ++i) {
matrix[i] = new int[n];
for (int j = 0; j < n; ++j) {
cin >> matrix[i][j];
}
}
cout << determinant(matrix, n);
return 0;
}

Related

Memoization Approach for Gold Mine Problem on GFG

I am trying to solve the Gold Mine problem on GFG using a memoization based approach of dynamic programming. Here is the code I have written.
int dp[50][50];
int traverse(int x,int y,int n,int m, vector<vector<int>> M){
if((x<n and x>=0) and (y<m and y>=0))
{
if(dp[x][y]!=-1)
return dp[x][y];
else{
int right=M[x][y]+traverse(x,y+1,n,m,M);
int right_up=M[x][y]+traverse(x-1,y+1,n,m,M);
int right_down=M[x][y]+traverse(x+1,y+1,n,m,M);
return dp[x][y]=max(max(right,right_up),right_down);}
}
return 0;
}
int maxGold(int n, int m, vector<vector<int>> M)
{
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
dp[i][j]=-1;
}
}
int ans=0;
for(int i=0;i<n;i++){
ans=max(ans,traverse(i,0,n,m,M));
}
return ans;
}
The question says that we can start from any cell in the first column.
As the specific cell is not specified, I have tried finding out the maximum of all possible answers with each cell of the first column as the starting point. But this is giving a TLE, which is expected because the above code would take o(n^2*m) time.
Can anyone help me out with how to get around this problem of optimally figuring out which cell to start from so that the memoization based approach works under the time constraints provided?
Use call by const reference for the STL container. You performed thousands of copies of the full, read-only input.
int dp[55][55];
int traverse(int x,int y,int n,int m, const vector<vector<int>>&M){
. . .
}
int maxGold(int n, int m, const vector<vector<int>>&M)`
{
...
}
here is my solution:
class Solution{
public:
int maxGold(int n, int m, vector<vector<int>> M)
{
vector<vector<int>> f(n + 10, vector<int>(m + 10, 0));
for(int i = 0; i < n; i++){
f[i][0] = M[i][0];
}
for(int j = 1; j < m; j++){
for(int i = 0; i < n; i++){
if(i == 0){
f[i][j] = max(f[i][j-1], f[i+1][j-1]) + M[i][j];
}else if(i == n-1){
f[i][j] = max(f[i][j-1], f[i-1][j-1]) + M[i][j];
}else{
f[i][j] = max({f[i][j-1], f[i-1][j-1], f[i+1][j-1]}) + M[i][j];
}
}
}
int res = 0;
for(int i = 0; i < n; i++){
res = max(res, f[i][m-1]);
}
return res;
}
};

change my recursive solution into a dynamic programming solution

here I am trying to convert my recursive solution into a dynamic solution but I am getting problem in converting. I am trying to count minimum possible coin to make value. what I am doing is I am taking all possible coin and putting inside a vector and finally in main function I will find and minimum of my vector and that will be my answer
int rec(vector<int>coins,int n,int sum,int counter)
{
if(sum==0)
{
return 1;
}
if(n==0)
{
return 0;
}
int total=rec(coins,n-1,sum,counter);
if(sum-coins[n-1]>=0)
{
total+=rec(coins,n,sum-coins[n-1],counter+1);
if(sum-coins[n-1]==0)
{
vec.push_back(counter+1);
}
}
return total;
}
you should first try to solve this type of problems by yourself.
BTW:
#define BIG 2147483647
int min_coin(int *coins, int m, int desire_value)
{
int dp[desire_value+1];
dp[0] = 0;
for (int i=1; i<=desire_value; i++)
dp[i] = BIG;
for (int i=1; i<=desire_value; i++)
{
for (int j=0; j<m; j++)
if (coins[j] <= i)
{
int diff = dp[i-coins[j]];
if (diff != BIG && diff + 1 < dp[i])
dp[i] = diff + 1;
}
}
if(dp[desire_value]==BIG)
return -1;
return dp[desire_value];
}
you can easily convert dp and coins to vector. vector is like array.(beware for allocate vector for dp you should reserve space in vector see here.)

N-Queen Problem: Cannot figure out why my solution is not working

I was having a go at the standard N-Queens problem for an upcoming interview.
I have tried to dry run my code and it seems to work fine. I can't spot the error in my code.
I am traversing it column by column, and using backtracking to recur back from an incorrect path.
Can anyone help me with why this doesn't give me the desired output (details below)?
Here's the problem statement
#include<bits/stdc++.h>
using namespace std;
void solve(vector<vector<int>> &ans, vector<int> &curr, int col, int n){
if(col==n){
ans.push_back(curr);
return;
}
bool flag=false;
for(int row=0; row<n; row++){
if(col==0){
curr.push_back(row);
solve(ans, curr, col+1, n);
curr.pop_back();
}
else{
for(int i=0; i<curr.size(); i++){
if((curr[i] == row) || (abs(row-curr[i]) == (col-i))){
flag=true;
break;
}
}
if(flag)
continue;
curr.push_back(row);
solve(ans, curr, col+1, n);
curr.pop_back();
}
}
}
int main()
{
int t;
cin>>t;
while(t--){
int n;
cin>>n;
vector<vector<int>> ans;
vector<int> curr;
solve(ans, curr, 0, n);
for (int i = 0; i < ans.size(); i++) {
cout << "[";
for (int j = 0; j < ans[i].size(); j++)
cout << ans[i][j]+1 << " ";
cout << "]";
}
cout << endl;
}
return 0;
}
A sample input would look like:
2
1
4
and the corresponding output would be:
[1 ]
[2 4 1 3 ] [3 1 4 2 ]
The compiler gives me an output (for my code):
[1 ]
The bool flag variable (used to check if placing a queen at (row, col) would intersect with any existing queens in curr) is currently being re-used across rows.
So, if you place the line bool flag=false; just above for(int i=0; i<curr.size(); i++){, it should produce the correct output for your test case.
Other notes:
It might be easier to create a separate function bool does_intersect(const vector<int>& cur, int row, int col) to check the queen intersection condition so that the bool flag variable isn't needed.
The if(col==0){ condition can be removed since it doesn't do anything that the else part cannot already handle.
This solution passes LeetCode's online judge for N Queens problem, and uses three flags to solve the problem:
#include <string>
#include <vector>
class Solution {
public:
std::vector<std::vector<std::string>> solveNQueens(int n) {
std::vector<std::vector<std::string>> possibilities;
std::vector<std::string> n_queens(n, std::string(n, '.'));
std::vector<int> flag_col(n, 1);
std::vector<int> flag_diag_a(2 * n - 1, 1);
std::vector<int> flag_diag_b(2 * n - 1, 1);
solveNQueens(possibilities, n_queens, flag_col, flag_diag_a, flag_diag_b, 0, n);
return possibilities;
}
private:
void solveNQueens(std::vector<std::vector<std::string>>& possibilities,
std::vector<std::string>& n_queens,
std::vector<int>& flag_col, std::vector<int>& flag_diag_a, std::vector<int>& flag_diag_b,
int row, int& n) {
if (row == n) {
possibilities.push_back(n_queens);
return;
}
for (int col = 0; col != n; col++) {
if (flag_col[col] && flag_diag_a[row + col] && flag_diag_b[n - 1 + col - row]) {
flag_col[col] = flag_diag_a[row + col] = flag_diag_b[n - 1 + col - row] = 0;
n_queens[row][col] = 'Q';
solveNQueens(possibilities, n_queens, flag_col, flag_diag_a, flag_diag_b, row + 1, n);
n_queens[row][col] = '.';
flag_col[col] = flag_diag_a[row + col] = flag_diag_b[n - 1 + col - row] = 1;
}
}
}
};
For interview, you should not probably use:
#include<bits/stdc++.h>
using namespace std;
and make sure to write clean codes.
N Queens is a low frequency interview question. There are much better questions to be asked in the interviews (such as Number of Islands), probably you would not get N Queens. But, it's good to practice.
This is a pretty simple way to solve the problem of the N-Queens using backtracking:
#include <bits/stdc++.h>
using namespace std;
int m[20][20];
bool ended = false;
void print(int n){
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
cout<<(m[i][j] == -1? "O" : "-")<<" ";
}
cout<<endl;
}
}
void fill(int val, int row, int col, int n){
int d = 1;
for(int i = col + 1; i < n; i++, d++){
m[row][i] += val;
if(row - d >= 0) m[row - d][i] += val;
if(row + d < n) m[row + d][i] += val;
}
}
void solve(int n, int col = 0){
if(ended) return;
if(col == n){ print(n); ended = true; return; }
for(int i = 0; i < n; i++){
if(m[i][col] == 0){
m[i][col] = -1;
fill(1, i, col, n);
solve(n, col + 1);
m[i][col] = 0;
fill(-1, i, col, n);
}
}
}
int main(){
memset(m, 0, sizeof(m));
solve(8); //dimension of board
return 0;
}
The idea is to always look forward. Place a queen in a slot that is 0 in the matrix. After that, add 1 in all slots where she can move to. When you return from the backtracking, subtract 1 from the same slots you just added and continue trying.

Juggling algorithm regarding Right Array rotation

Recently I learnt about the array rotation in linear time using Juggling algorithm. Here is the snippet regarding the left rotation of the array.
void ArrayRotate (int A[], int n, int k)
{
int d=-1,i,temp,j;
for(i=0;i<gcd(n,k);i++)
{
j=i;
temp=A[i];
while(1)
{
d=(j+k)%n;
if(d==i)
break;
A[j]=A[d];
j=d;
}
A[j]=temp;
}
}
but now I am stuck as how to use this Juggling algorithm to rotate the array in the Right Direction.
1,2,3,4,5 (given array)
5,1,2,3,4 (after 1 right rotation)
(I had solved this question using the brute force method and reversal method.)
As already mentioned, you should use std::rotate if you are allowed to.
Your implementation has a bug. Here is a fixed implementation.
void ArrayRotate(int A[], int n, int k) {
int d = -1, i, temp, j;
int g = gcd(n, k);
for (i = 0; i < g; ++i) {
j = i;
temp = A[i];
while (true) {
d = (j + k) % n;
if (d == i) {
break;
}
A[j] = A[d];
j = d;
}
A[j] = temp;
}
}
Also note that I took out gcd calculation out of loop condition. It does not technically affect complexity, but it's enough to compute the gcd only once.
To rotate the array k times to the right, just rotate it n - k times to the left.
void ArrayRotateRight(int A[], int n, int k) {
ArrayRotate(A, n, n - k);
}
Or change the 8th line to be d = (j - k + n) % n;
Not sure if you're doing this as an intellectual exercise, or for production code, but for production code use the STL rotate algorithm:
#include<iostream>
#include<algorithm>
using namespace std;
void display(int* a, int length)
{
for (int i = 0; i < length; ++i)
cout << a[i] << " ";
cout << endl;
}
int main()
{
const int len = 5;
int arr[] = { 1,2,3,4,5 };
display(arr, len);
rotate(arr, arr + 1, arr + len); // arr + x means left by x
display(arr, len);
rotate(arr, arr + len - 1, arr + len); // arr + len - x means right by x
display(arr, len);
}

lexicographically smallest string after rotation

I am trying to solve this problem in spoj
I need to find the number of rotations of a given string that will make it lexicographically smallest among all the rotations.
For example:
Original: ama
First rotation: maa
Second rotation: aam This is the lexicographically smallest rotation so the answer is 2.
Here's my code:
string s,tmp;
char ss[100002];
scanf("%s",ss);
s=ss;
tmp=s;
int i,len=s.size(),ans=0,t=0;
for(i=0;i<len;i++)
{
string x=s.substr(i,len-i)+s.substr(0,i);
if(x<tmp)
{
tmp=x;
t=ans;
}
ans++;
}
cout<<t<<endl;
I am getting "Time Limit Exceeded" for this solution. I don't understand what optimizations can be made. How can I increase the speed of my solution?
You can use a modified suffix array. I mean modified because you must not stop on word end.
Here is the code for a similar problem I solved (SA is the suffix array):
//719
//Glass Beads
//Misc;String Matching;Suffix Array;Circular
#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>
#include <cmath>
#define MAX 10050
using namespace std;
int RA[MAX], tempRA[MAX];
int SA[MAX], tempSA[MAX];
int C[MAX];
void suffix_sort(int n, int k) {
memset(C, 0, sizeof C);
for (int i = 0; i < n; i++)
C[RA[(i + k)%n]]++;
int sum = 0;
for (int i = 0; i < max(256, n); i++) {
int t = C[i];
C[i] = sum;
sum += t;
}
for (int i = 0; i < n; i++)
tempSA[C[RA[(SA[i] + k)%n]]++] = SA[i];
memcpy(SA, tempSA, n*sizeof(int));
}
void suffix_array(string &s) {
int n = s.size();
for (int i = 0; i < n; i++)
RA[i] = s[i];
for (int i = 0; i < n; i++)
SA[i] = i;
for (int k = 1; k < n; k *= 2) {
suffix_sort(n, k);
suffix_sort(n, 0);
int r = tempRA[SA[0]] = 0;
for (int i = 1; i < n; i++) {
int s1 = SA[i], s2 = SA[i-1];
bool equal = true;
equal &= RA[s1] == RA[s2];
equal &= RA[(s1+k)%n] == RA[(s2+k)%n];
tempRA[SA[i]] = equal ? r : ++r;
}
memcpy(RA, tempRA, n*sizeof(int));
}
}
int main() {
int tt; cin >> tt;
while(tt--) {
string s; cin >> s;
suffix_array(s);
cout << SA[0]+1 << endl;
}
}
I took this implementation mostly from this book. There is an easier to write O(n logĀ²n) version, but may not be efficient enough for your case (n=10^5). This version is O(n log n), and it's not the most efficient algorithm. The wikipedia article lists some O(n) algorithms, but I find most of them too complex to write during a programming contest. This O(n log n) is usually enough for most problems.
You can find some slides explaining suffix array concept (from the author of the book I mentioned) here.
I know this comes very late but I stumbled across this from google on my search for an even faster variant of this algorithm. Turns out a good implementation is found at github: https://gist.github.com/MaskRay/8803371
It uses the lyndon factorization. That means it repeatly splits the string into lexicographically decreasing lyndon words. Lyndon word are strings that are (one of) the minimal rotations of themselves. Doing this in a circular way yields the lms of the string as the last found lyndon word.
int lyndon_word(const char *a, int n)
{
int i = 0, j = 1, k;
while (j < n) {
// Invariant: i < j and indices in [0,j) \ i cannot be the first optimum
for (k = 0; k < n && a[(i+k)%n] == a[(j+k)%n]; k++);
if (a[(i+k)%n] <= a[(j+k)%n]) {
// if k < n
// foreach p in [j,j+k], s_p > s_{p-(j-i)}
// => [j,j+k] are all suboptimal
// => indices in [0,j+k+1) \ i are suboptimal
// else
// None of [j,j+k] is the first optimum
j += k+1;
} else {
// foreach p in [i,i+k], s_p > s_{p+(j-i)}
// => [i,i+k] are all suboptimal
// => [0,j) and [0,i+k+1) are suboptimal
// if i+k+1 < j
// j < j+1 and indices in [0,j+1) \ j are suboptimal
// else
// i+k+1 < i+k+2 and indices in [0,i+k+2) \ (i+k+1) are suboptimal
i += k+1;
if (i < j)
i = j++;
else
j = i+1;
}
}
// j >= n => [0,n) \ i cannot be the first optimum
return i;
}