How to speed up reading matrices from file and multiplying them? - java

1 What I have on input
File input.txt looking like this:
3 2
1 2
1 2
3 4
4 2
1 3
1 2
2 1
Where:
3 2 3-number of matrices in file; 2-length of matrices (they all square)
1 2 i=1 j=2 -positions of requested value inmatrixResult[i][j]
1 2 matrix 1
3 4
4 2 matrix 2
1 3
1 2 matrix 3
2 1
Number of matrices can be any <=130
Matrices size can be any <=130
2 What should I have on output
One number, which is member of result matrix, specified by position values (1, 2 in this case).
Where result matrix=matrix 1 * matrix 2
For example final result is: 20
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
/**
* Created by Pazuk on 28.01.2018.
*/
// Main idea:
// Step 1. Get all values from input file and according with it build array with numbers for matrices
// Step 2.
// Loop iteration:
// - get numbers from array and create next matrix array
// - multiply actual matrix with next matrix, get result matrix
// - mark result matrix as actual matrix
// Next iteration...
// Step 3. After last iteration, get from result matrix requested number (positions specified in input file)
public class Main {
static int[] list;
static boolean fileCheckOk=true;
static int m;
static int n;
static int a;
static int b;
static int[][] matrixA;
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
long time = System.currentTimeMillis() - startTime;
System.out.println(time);
readFile();
time = System.currentTimeMillis()-startTime;
System.out.println(time);
if(fileCheckOk){
calculate();
PrintWriter writer=new PrintWriter("output.txt");
writer.print(matrixA[a-1][b-1]);
writer.close();
}
time = System.currentTimeMillis()-startTime;
System.out.println(time);
}
static void readFile() throws IOException {
Reader reader=new FileReader(file);
StreamTokenizer tokenizer=new StreamTokenizer(reader);
//general input values:
tokenizer.nextToken();
m=(int)tokenizer.nval; // number of matricis
tokenizer.nextToken();
n=(int)tokenizer.nval; // matrices size
tokenizer.nextToken();
a=(int)tokenizer.nval; // position i of requested number
tokenizer.nextToken();
b=(int)tokenizer.nval; // position j of requested number
list=new int[m*n*n]; // array length according with quantity of matricis and their size
int i=0;
while(tokenizer.nextToken()!=StreamTokenizer.TT_EOF){
list[i]=(int)tokenizer.nval;
i++;
}
if(reader!=null) {
reader.close();
}
/*if(m>=1 && m<=130 && n>=1 && n<=130 && a>=1 && a<=n && b>=1 && b<=n){
fileCheckOk=true;
}*/
}
static void calculate(){ // calculate matrices
int f, i, j, k;
int r=0;
int t;
int temp;
int[] thatColumn=new int[n];
int[] thisRow=new int[n];
int result=0;
matrixA=new int[n][n]; // actual matrix
for(f=0; f< m; f++){ // number of iterations==matrices quantity
int[][] matrixB=new int[Main.n][Main.n]; // next matrix
for(i=0; i< Main.n; i++){
for(j=0; j< Main.n; j++){
matrixB[i][j]=list[r];
r++;
}
}
if(f>0){
int[][] matrixC=new int[Main.n][Main.n]; //result matrix
for(j=0; j< Main.n; j++){
for(k=0; k< Main.n; k++){
thatColumn[k]=matrixB[k][j];
}
for(i=0; i< Main.n; i++){
thisRow=matrixA[i];
result=0;
for(k=0; k<Main.n; k++){
temp=thisRow[k]*thatColumn[k];
result=result+temp;
}
matrixC[i][j]=result;
}
}
/*for(i=0; i< Main.n; i++){
for(j=0; j< Main.n; j++){
t=matrixA[i][k];
for(j=0; j< Main.n; j++){
temp=t*matrixB[k][j]; // multiplying...
matrixC[i][j]=matrixC[i][j]+temp; // ...matrces
}
}
}*/
matrixA=matrixC;
} else {
matrixA=matrixB;
}
}
}
}
My code works and gives on output right value. But this code don't pass test. Because of it works too slow.
What can I do to make this do it faster?
Maybe #1. Process info from file other way? Now i scan nextInt. First
4 put into variables. All left into int[ ] array ( look readFile() method ).
And after take values for A, B, ect. matrices from this array.
Maybe #2. Change way of multiplying of matrices? Now I do it with
basic "direct" way:
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
for(int k=0; k<o; k++){
resultMatrix[i][j]+=mA[i][k]*mB[k][j];
}
}
}
Well, almost this way. A bit faster ( look calculate( ) method ).
Maybe #3. Make calculations (or something other) in parallel threads?
Maybe #4. Instead of: "build" A and B matrices from int[ ] array values
at first for multiply them after Try to: make calculation of
resultMatrix using directly values from one-dimensional array int [ ]?

Related

How to write a sufficient program for weed lawn problem?

I need to write a program for the problem below :
you have a lawn (a matrix of n*m) and in some cells, weed has grown, and you want to remove them.
there are two operations :
stomping on a cell: by doing so, one of the weeds in that cell dies and two new weeds appear in cells [i][(j+1)%n) and [(i+1)%n][j].
pulling out a weed: this removes the weed and takes the energy of E_(i,j).
Now given a matrix of energy(how much energy removing one weed from each cell takes) and the places where weeds have grown, we want to calculate the least amount of energy we need to get rid of all the weeds.
import java.util.Scanner;
import java.util.*;
import java.io.*;
public class TEST{
public static void main (String[] args)
{
int n=0, m=0 , k=0;
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
m = scanner.nextInt();
k = scanner.nextInt();
scanner.nextLine();
int [][] lawn = new int [n][m];
int [][] NumOfWeed = new int [n][m];
for(int j=0; j<m ; j++){
for(int i=0; i < n ; i ++){
lawn[i][j]= scanner.nextInt();
}
scanner.nextLine();
}
int i_index =0, j_index =0;
for(int i=0; i < k ; i ++){
i_index= scanner.nextInt();
j_index=scanner.nextInt();
scanner.nextLine();
NumOfWeed[i_index][j_index] ++;
}
boolean changing = true;
while(changing){
changing = false;
for(int j=0; j<m ; j++){
for(int i=0; i < n ; i ++){
if(NumOfWeed[i][j]>0){
if(lawn[i][j] > lawn[(i+1)%n][j]+lawn[i][(j+1)%n]){
NumOfWeed[(i+1)%n][j] =NumOfWeed[(i+1)%n][j] + NumOfWeed[i][j];
NumOfWeed[i][(j+1)%n] = NumOfWeed[i][(j+1)%n] + NumOfWeed[i][j];
NumOfWeed[i][j]=0;
changing = true;
}
}
}
}
}
int sumEnergy =0;
for(int j=0; j<m ; j++){
for(int i=0; i < n ; i ++){
sumEnergy = sumEnergy + lawn[i][j]*NumOfWeed[i][j];
}
}
scanner.close();
System.out.println(sumEnergy);
}
}
you can see my own code above, but as you see it's not optimal at all.
any ideas on how I can change it so that it takes less time to perform?
Here is one way of doing it, that should lead to correct results but isn't optimized:
Initialize a matrix a (size n * m) for the actual energy needed if you stomp optimally. Set all values to -1.
Find all minima in the original energy matrix ignoring values where the corresponding position in a is not -1. Set the positions of the minima in a to its value.
While there are changes and a isn't completely filled do the following: For each value (i, j) in a that is -1 and the values to the right and down (with wrap-around) are not -1 set (i, j) to the minimum of the sum of the 2 stomped position and the original energy needed for (i, j).
Continue with 2. until a is completely filled. Then "multiply" the lawn matrix with a (no matrix multiplication, just same position with same position) and sum up the values to get the total.

2D Array with variable internal array length JAVA

Im currently writing some code that print Pascal's Triangle. I need to use a 2D array for each row but don't know how to get the internal array to have a variable length, as it will also always changed based on what row it is int, for example:
public int[][] pascalTriangle(int n) {
int[][] array = new int[n + 1][]
}
As you can see I know how to get the outer array to have the size of Pascal's Triangle that I need, but I don't know how to get a variable length for the row that corresponds with the line it is currently on.
Also how would I print this 2D array?
Essentially what you want to happen is get the size of each row.
for(int i=0; i<array.size;i++){//this loops through the first part of array
for(int j=0;j<array[i].size;j++){//this loops through the now row
//do something
}
}
You should be able to use this example to also print the triangle now.
This is my first answer on StackOverFlow. I am a freshman and have just studied Java as part of my degree.
To make every step clear, I will put different codes in different methods.
Say n tells us how many rows that we are going to print for the triangle.
public static int[][] createPascalTriangle(int n){
//We first declare a 2D array, we know the number of rows
int[][] triangle = new int[n][];
//Then we specify each row with different lengths
for(int i = 0; i < n; i++){
triangle[i] = new int[i+1]; //Be careful with i+1 here.
}
//Finally we fill each row with numbers
for(int i = 0; i < n; i++){
for(int j = 0; j <= i; j++){
triangle[i][j] = calculateNumber(i, j);
}
}
return triangle;
}
//This method is used to calculate the number of the specific location
//in pascal triangle. For example, if i=0, j=0, we refer to the first row, first number.
public static int calculateNumber(int i, int j){
if(j==0){
return 1;
}
int numerator = computeFactorial(i);
int denominator = (computeFactorial(j)*computeFactorial(i-j));
int result = numerator/denominator;
return result;
}
//This method is used to calculate Factorial of a given integer.
public static int computeFactorial(int num){
int result = 1;
for(int i = 1; i <= num; i++){
result = result * i;
}
return result;
}
Finally, in the main method, we first create a pascalTriangle and then print it out using for loop:
public static void main(String[] args) {
int[][] pascalTriangle = createPascalTriangle(6);
for(int i = 0; i < pascalTriangle.length; i++){
for(int j = 0; j < pascalTriangle[i].length; j++){
System.out.print(pascalTriangle[i][j] + " ");
}
System.out.println();
}
}
This will give an output like this:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

Java cut the sticks

I am very new to Java and I was trying to solve this problem on Hackerrank:
Here's the task:
https://www.hackerrank.com/challenges/cut-the-sticks
You are given N sticks, where the length of each stick is a positive
integer. A cut operation is performed on the sticks such that all of
them are reduced by the length of the smallest stick.
Suppose we have six sticks of the following lengths:
5 4 4 2 2 8
Then, in one cut operation we make a cut of length 2 from each of the six
sticks. For the next cut operation four sticks are left (of non-zero length), > whose lengths are the following:
3 2 2 6
The above step is repeated until no sticks are left.
Given the length of N sticks, print the number of sticks that are left before > each subsequent cut operations.
Note: For each cut operation, you have to recalcuate the length of smallest
sticks (excluding zero-length sticks).
Here is my attempt at it, but it doesnt seem to be working. The output gets stuck in while loop (4 gets printed out infinitely)
import java.io.*;
import java.util.*;
public class Solution {
private static int findMin (int[] A)
{
int min = A[0];
for (int i =0; i<A.length; i++)
{
if (A[i] < min)
{
min = A[i];
}
}
return min;
}
private static int countNonZeros (int[] A)
{
int zeros = 0;
for (int i =0; i<A.length; i++)
{
if (A[i] == 0)
{
zeros++;
}
}
int nonZeros = A.length - zeros;
return nonZeros;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] A = new int[n];
for (int i=0; i<n; i++)
{
A[i] = scanner.nextInt();
}
int nums = countNonZeros(A);
while (nums > 0)
{
int mins = findMin(A);
for (int j = 0; j<A.length; j++)
{
A[j]=A[j]-mins;
}
nums = countNonZeros(A);
System.out.println(nums);
}
}
}
Any help is appreciated
(PS I know I can just look the solution up somewhere, but I want to know why my code isn't working)
The problem that you have is that your findMin is not excluding zero-length elements, so once you have a zero that will be the min, and as a result an iteration of the while loop will be the same as the previous iteration, having subtracted 0 from each of the elements of A.

Scanner object keeps expecting input

I have the following code in which a matrix is defined through system input:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//define size of matrix
int size = in.nextInt();
int primeSum = 0;
int secSum = 0;
int[] matrix = new int[size*size];
//create matrix
for (int i=0; i<size*size;i++) {
matrix[i] = in.nextInt();
}
in.close();
//sum primary diagonal
for (int i=0; i < size*size;i += (size + 1)) {
primeSum = primeSum + matrix[i];
}
////sum secondary diagonal
// for (int i=(size - 1); i < size*size; i += (size - 2)) {
// secSum = secSum + matrix[i];
// }
System.out.println(Math.abs(secSum - primeSum));
}
}
The code above works in that it allows the user to define an NxN matrix through inputting N as the size - so in the case size = 2 the user would define 4 matrix elements. However, after commenting back in the code for the secondary diagonal, the scanner object keeps expecting input past 4 integers - I have no idea why this would affect the program as I close the input stream before that block of code is reached.
You wrote a potentially infinite loop. I.e. if size is not greater than 2, then i will count down or stay 0. You should cover these corner cases, then your code will be fine.
As far as I can see, you're emulating a two-dimensional array on a one-dimensional. This is something that's hard to understand and easy to mess up. You are better off with a two-dimensional array and some nested loops:
int[][] matrix = new int[size][size];
//create matrix
for (int i=0; i<size; i++) {
for (int j=0; j<size; j++) {
matrix[i][j] = in.nextInt();
}
}
// and so on...
Your this part of code:
for (int i=0; i<size*size;i++) {
matrix[i] = in.nextInt();
}
calls the method nextInt which demands for input as long as the array is filled.

Weighted random numbers in 2D Array - Processing

I would like to fill a 3x3 2D array with values 1,2,3.
I need each number to appear for a given times.
For example:
1 to appear 2 times
2 to appear 4 times
3 to appear 3 times
What I need is to store this numbers to array in a random position.
For Example:
1,2,2
3,2,2
1,3,3
I already did this in a simple way using only 2 different numbers controlled by a counter. So I loop through the 2D array and applying random values of number 1 and number 2.
I'm checking if the value is 1 and add it in the counter and the same with number 2. if one of the counter exceeds the number I have set as the maximum appear times then it continues and applies the other value.
Is there any better approach to fill the 3 numbers in random array position?
See code below:
int [][] array = new int [3][3];
int counter1 =0;
int counter2 =0;
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
array[i][j] = (int)random(1, 3); //1,2
if (arrray[i][j]==1) {
counter1++;
} else if (array[i][j] ==2) {
counter2++;
}
//if it is more than 5 times in the array put only the other value
if (counter1>5) {
array[i][j] = 2;
}
//if it is more than 4 times in the array put only the other value
else if (counter2>4) {
array[i][j] = 1;
}
}
}
I finally did this according to this discussion:
How can I generate a random number within a range but exclude some?, with 1D array for tesing, but it does not always works.
Please see attached code:
int []values = new int[28];
int counter1=0;
int counter2=0;
int counter3=0;
for (int i=0; i<values.length; i++) {
if (counter1==14) {
ex = append(ex, 5);
}
if (counter2==4) {
ex =append(ex, 6);
}
if (counter3==10) {
ex =append(ex, 7);
}
values[i] = getRandomWithExclusion(5, 8, ex);
if (values[i]==5) {
counter1++;
} else if (values[i] ==6) {
counter2++;
} else if (values[i] ==7) {
counter3++;
}
}
int getRandomWithExclusion(int start, int end, int []exclude) {
int rand = 0;
do {
rand = (int) random(start, end);
}
while (Arrays.binarySearch (exclude, rand) >= 0);
return rand;
}
I would like to fill the 1D array with values of 5,6 or 7. Each one a specific number. Number 5 can be added 14 times. Number 6 can be added 4 times. Number 7 can be added 10 times.
The above code works most of the times, however somethimes it does not. Please let me know if you have any ideas
This is the Octave/Matlab code for your problem.
n=3;
N=n*n;
count = [1 2; 2 4; 3 3];
if sum(count(:,2)) ~= N
error('invalid input');
end
m = zeros(n, n);
for i = 1:size(count,1)
for j = 1:count(i,2)
r = randi(N);
while m(r) ~= 0
r = randi(N);
end
m(r) = count(i,1);
end
end
disp(m);
Please note that when you address a 2D array using only one index, Matlab/Octave would use Column-major order.
There are a ton of ways to do this. Since you're using processing, one way is to create an IntList from all of the numbers you want to add to your array, shuffle it, and then add them to your array. Something like this:
IntList list = new IntList();
for(int i = 1; i <= 3; i++){ //add numbers 1 through 3
for(int j = 0; j < 3; j++){ add each 3 times
list.append(i);
}
}
list.shuffle();
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
array[i][j] = list.remove(0);
}
}
You could also go the other way: create an ArrayList of locations in your array, shuffle them, and then add your ints to those locations.

Categories