UVA#523 Minimum Transport Cost - java

UVA link: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=464
I'm lost as to what I'm doing now. I don't know why I'm producing incorrect values. I printed out the array after I looked for shortest path. And it produces this:
[0, 3, 8, 8, 4]
[3, 0, 5, 11, 7]
[8, 5, 0, 9, 12]
[8, 11, 9, 0, 4]
[4, 7, 12, 4, 0]
The sample input is:
1
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
With the sample input, I produce the output:
From 1 to 3 :
Path: 1-->2-->3
Total cost :8
From 3 to 5 :
Path: 3-->2-->5
Total cost :12
From 2 to 4 :
Path: 2-->5-->4
Total cost :11
If I look at my array, it seems to be correct. But the correct answer is:
From 1 to 3 :
Path: 1-->5-->4-->3
Total cost : 21
From 3 to 5 :
Path: 3-->4-->5
Total cost : 16
From 2 to 4 :
Path: 2-->1-->5-->4
Total cost : 17
I think I missed adding the tax, but I don't know where to add it. I tried adding tax[j] to the path[i][j] while doing the shortest path, and then subtracting the tax[x-1] and tax[y-1] (x-1 is my source, y-1 is my destination). It doesn't work, and messes up my path array (it gives value to loops; I don't really need that). I really don't know where to put the tax.
Here is my code for reference:
import java.util.*;
public class Main{
public static final int INF = 9999999;
public static int[][] path;
public static int[][] next;
public static int[] tax;
public static void main(String[] adsf){
Scanner pp = new Scanner(System.in);
int testCases = pp.nextInt();
boolean first = true;
pp.nextLine();
pp.nextLine();
while(testCases-- >0){
String[] s1 = pp.nextLine().split(" ");
int size = s1.length;
path = new int[size][size];
next = new int[size][size];
for(int i = 0; i < path.length; i++)
Arrays.fill(path[i],INF);
tax = new int[size];
for(int j = 0; j < path[0].length; j++){
path[0][j] = Integer.parseInt(s1[j]);
if(path[0][j]==-1)
path[0][j]=INF;
}
for(int i = 1; i < path.length;i++){
s1 = pp.nextLine().split(" ");
for(int j = 0; j < path[0].length; j++){
path[i][j] = Integer.parseInt(s1[j]);
if(path[i][j]==-1)
path[i][j]=INF;
}
}
for(int k=0; k<tax.length;k++){
tax[k] = pp.nextInt();
} pp.nextLine();
apsp();
int x,y;
//for(int i = 0; i < size; i++)
//System.out.println(Arrays.toString(path[i]));
while(pp.hasNextInt()){
if(!first)
System.out.println();
x=pp.nextInt();
y=pp.nextInt();
int cost = path[x-1][y-1];
System.out.println("From "+x+" to "+y+" :");
System.out.print("Path: ");
ArrayList<Integer> print = getpath(x-1,y-1);
for(int l = 0; l < print.size(); l++){
System.out.print(print.get(l)+1);
if(l!=print.size()-1) System.out.print("-->");
else System.out.println();
}
System.out.println("Total cost :"+cost);
first = false;
}
}
}
public static void apsp(){
for(int k=0;k<path.length;k++){
for(int i=0;i<path.length;i++){
for(int j=0;j<path.length;j++){
if (path[i][k] + path[k][j] + tax[j] < path[i][j] + tax[j]) {
path[i][j] = path[i][k]+path[k][j];
next[i][j] = k;
} else{
path[i][j] = path[i][j];
}
}
}
}
}
public static ArrayList<Integer> getpath (int i, int j) {
ArrayList<Integer> pat = getMidPath(i,j);
pat.add(0,i);
pat.add(j);
return pat;
}
public static ArrayList<Integer> getMidPath(int i, int j){
if(next[i][j]==0)
return new ArrayList<Integer>();
ArrayList<Integer> pat = new ArrayList<Integer>();
pat.addAll(getMidPath(i,next[i][j]));
pat.add(next[i][j]);
pat.addAll(getMidPath(next[i][j],j));
return pat;
}
}

The tax is applied:
whenever any cargo passing through one city, except for the source and the destination cities.
So you if you have a path:
a -> b -> c -> d
Then you should include the cost of the path (a,b) + tax(b) + (b,c) + tax(c) + (c,d).
For implementing that into your algorithm, you should be able to add the city taxes to the path lengths like this:
If you know you're starting at a and ending at d, then any directed path to a city x, where x isn't a or b, should be treated as the cost of x + the tax at city x.
You will need to revert the path cost values back to the original ones for the next path you want to calculate the value of and re-add the tax values in for the new starting point and destination.

Related

Maximum difference between final and initial sum

I am new to programming and having trouble solving one task. I have several input example. First line contains two numbers m (number of digits on paper, 1<m<1000) and h (limit on the number of operations, 1<h<1000). I have the opportunity, no more than h times, to take any number from a piece of paper (means m), then paint over one of the old digits, and write a new arbitrary digit in its place. By what maximum value can I be able to increase the sum of all the numbers on the piece of paper?
First example:
Input:
5 2 //m and h
1 3 1 4 5 //m = 5, so I can add 5 arbitrary numbers and h=2, so I can change 2 numbers
Output:
16 // cause I changed 1 and 1 to 9 and 9, so the difference 8 and 8 and the sum is 16
Second example:
Input:
3 1
99 5 85
Output:
10 //85 to 95, so the difference is 10
Third example:
Input:
1 10
9999
Output:
0 // nothing to be change
What I have for now:
Scanner sc = new Scanner(System.in);
System.out.println("Enter the number: ");
int m = sc.nextInt();
int h = sc.nextInt();
System.out.println("Entered: " + m);
System.out.println("Entered: " + h);
int[] numbers = new int[m];
for(int i = 0; i < m; ++i) {
numbers[i] = sc.nextInt();
}
Arrays.sort(numbers);
//here is my logic: I am changing 1 to 9
for (int i = 0; i < h; i++) {
if (numbers[i] < 10) {
numbers[i] = 9;
}
else if (numbers[i] > 9 and numbers[i] < 100) {
numbers[i] = 99;
}
}
sc.close();
My logic can work for the first example, but for the second example it won't work. Can you assist me if I am using right logic or is there any easier way to solve this? Thanks in advance.
I quickly came up with below solution
public static void calculateMax(int m,int h, int[] arr){
int sum = 0;
ArrayList<Integer> al = new ArrayList<>();
for(int i=0;i<arr.length;i++){
String stringNum = Integer.toString(arr[i]);
int num = Integer.parseInt(stringNum.substring(0, 1));
if(num!=9){
al.add(Integer.parseInt(("9"+stringNum.substring(1)))-arr[i]);
continue;
}
al.add(0);
}
Collections.sort(al);
int j = al.size()-1;
for(int i=0;i<h && j>0;i++){
sum+=al.get(j--);
}
System.out.println(sum);
}
Here what I am doing is basically, calculating for each number what we can get as maximum by removing one digit and replacing by 9. And I am storing them in a list. Then we can sort that list and get 'h' largest numbers from stored list, and essentially getting the sum of them and printing it.
Break each input number into its digits times the appropriate power of 10. Sort these by powers of 10 descending, digits ascending. Apply your operation in this order.
E.g., 876, 12, 42 -> 800, 70, 6, 10, 2, 40, 2 -> 800, 10, 40, 70, 2, 2, 6.

Java to find if an array is a subset of another

Im having trouble to find out if a specific amount of numbers is in another array.The first array generates 10 random numbers and in the second array the user guesses 5 numbers.Im trying to find out if the user guessed any sequences.I used for loops to find out if numbers of user input is in any of the numbers from 1-5 in the array of 10 , if not it will check numbers 2-6 and so on.
For example, if the program had the following winning numbers:
23 56 67 06 43 22 59 24 90 66 and user entered: 01 06 43 22 89.
I keep getting index out of bounds.How do I fix this ?
// to check if user guessed a sequence
boolean guessed = false;
int counter = 0;
int i , j = 0;
for (i = 4; i < numbers.length; i++) { // users numbers
for ( j = 4; j < lottery.length; j++) { // first 5 numbers from array
if ( lottery[i] == numbers[j]) {
break;
}
if ( j == i) {
guessed = true;
}
}
}
It seems that a method similar to String::indexOf should be implemented in this task for the arrays trying to find an index of a subarray int indexOf(int[] search, int[] input).
Also, it might be needed to look for all possible subarrays of the search subarray (lottery). Thus, the mentioned method should be extended to look for a subrange of the search argument: int indexOf(int[] search, int[] input)
Straightforward implementation would be:
static int indexOf(int search[], int from, int to, int[] input) {
if (null == search || null == input || search.length > input.length) {
return -1;
}
for (int i = 0, n = input.length - (to - from); i <= n; i++) {
boolean found = true;
for (int j = from; found && j < to; j++) {
if (input[i + j - from] != search[j]) {
found = false;
}
}
if (found) {
return i;
}
}
return -1;
}
The widths and appropriate indexes from / to of the search subranges can be generated as follows (from the entire length of lottery to 2):
int[] numbers = {23, 56, 67, 06, 43, 22, 59, 24, 90, 66};
int[] lottery = {01, 06, 43, 22, 89};
for (int n = lottery.length; n > 1; n--) {
for (int m = 0; m <= lottery.length - n; m++) {
int ix = indexOf(lottery, m, m + n, numbers);
if (ix > -1) {
System.out.printf("Found subarray %s, width=%d from: %d to %d ",
Arrays.toString(Arrays.copyOfRange(lottery, m, m + n)), n, m, m + n - 1);
System.out.printf("at index: %d%n", ix);
}
}
}
Output
Found subarray [6, 43, 22], width=3 from: 1 to 3 at index: 3
Found subarray [6, 43], width=2 from: 1 to 2 at index: 3
Found subarray [43, 22], width=2 from: 2 to 3 at index: 4
A more efficient implementation would use Knuth - Morris - Pratt algorithm to bypass recurrent checks of the same values in the input array.

Add the consecutive digits of a birthdate recursively till it reaches to a single digit

I am developing a numerology application which has to provide a result which is similar to the following,
1 5 0 8 1 9 9 4
6 5 8 9 1 1 1
1 1 1 1 2 2
2 2 2 3 4
4 4 5 7
8 9 1
1 1
2
It has to add the consecutive digits and retain the first digit if the sum is of 2 digits.
I am missing something. Adding a while loop for the length of intList doesn't seem to work.
int date;
List<Integer> sumList = new ArrayList<Integer>();
Scanner s = new Scanner(System.in);
System.out.println("Enter the date");
date = s.nextInt();
int len = Integer.toString(date).length();
int[] convertarray = new int[len];
for (int index = 0; index < len; index++) {
convertarray[index] = date % 10;
date /= 10;
}
List<Integer> intList = new ArrayList<Integer>();
for (int i : convertarray) {
intList.add(i);
}
Collections.reverse(intList);
System.out.println(intList);
int sum = 0;
int size = intList.size();
for (int i = 0; i < intList.size() - 1; i++) {
sum = intList.get(i) + intList.get(i + 1);
int length = (int) (Math.log10(sum) + 1);
if (length > 1) {
int firstDigit = Integer.parseInt(Integer.toString(sum).substring(0, 1));
sum = firstDigit;
}
System.out.print(sum + " ");
sumList.add(sum);
}
System.out.println("\n");
intList.clear();
intList = sumList;
My output is something like,
1 5 0 8 1 9 9 4
6 5 8 9 1 1 1
A simple recursive solution:
public static void main(String[] args) throws Exception {
String birthday = "01091995";
int[] digits = Arrays.stream(birthday.split("")).mapToInt(Integer::parseInt).toArray();
recursiveFunction(digits);
}
private static void recursiveFunction(int[] digits) {
if(digits.length == 1) {
// Base Case
System.out.println(digits[0]);
} else {
// Recursive Case
System.out.println(Arrays.toString(digits));
int[] digitsProcessed = new int[digits.length -1];
for (int i = 0; i < digits.length - 1; i++) {
digitsProcessed[i] = digits[i] + digits[i+1]; // Logic
}
recursiveFunction(digitsProcessed);
}
}
This produces:
[0, 1, 0, 9, 1, 9, 9, 5] // 8 numbers
[1, 1, 9, 10, 10, 18, 14] // 7 numbers
[2, 10, 19, 20, 28, 32] // 6 numbers
[12, 29, 39, 48, 60] // 5 numbers
[41, 68, 87, 108] // 4 numbers
[109, 155, 195] // 3 numbers
[264, 350] // 2 numbers
614 // 1 number
Adding a while loop for the length of intList doesn't seem to work.
Well it can be done with loops, but it would be harder and messier.
An algorithm with recursion would be the following:
Init the array of integers.
Call the recursive function "F" with the array.
From now, the recursive function behaviour:
Check if the recieved array's length is 1.
If it is, print the element and terminate.
If it is not:
Print the recieved array.
Make a new array.
Put in this new array the result of processing the recieved one adding as intended.
Call the recursive function "F" with this new array.

Cut and Stack the Array

I have an array of int as input. The array will always be a length of 2^n. I want to cut the array in half and stack it. Repeat cutting and stacking until there is only one stack. For example:
int[] array = {1,2,3,4,5,6,7,8}
if we cut the array in half we and stack them it would be:
{1,2,| 3,4}
{5,6,| 7,8}
cut it and stack again:
{1,|2}
{5,|6}
{3,|4}
{7,|8}
again:
{1}
{5}
{3}
{7}
{2}
{6}
{4}
{8}
the desired output would be an array of int from the top to the end of the stack
int[] output = {1,5,3,7,2,6,4,8}
I have tried to construct the output array by looping the input array in a particular way. Note that when I reach the array I just start from the head again. I start at the array[i] where i = 0. I get the first number this way. then I increment i by n where n is the log(array.legnth) (base 2). This is how I get the second number. For the third number, we increment i by (n + n/2). For the fourth number, we increment i by n again. I am wondering is there a pattern? Or what would be your approach to solve this problem? I am looking for a solution in java or python.
Edit/Update:
I tried a new approach using queue. I basically keep cutting array in half and push both half of array into queue until arrays in queue all have length of 2 (or the stack is at height n). but my result is not correct. I think it has to do with the order I add the half arrays back into the queue.
import java.util.*;
public class StackArray{
public static void main(String[] args){
int[] array = {1,2,3,4,5,6,7,8};
int[] answer = stackArray(array);
for(int n : answer){
System.out.println(n);
}
}
public static int[] stackArray(int[] array){
int height = (int) (Math.log(array.length)/Math.log(2)) + 1;
Queue<int[]> queue = new LinkedList<int[]>();
ArrayList<Integer> list = new ArrayList<>();
queue.add(array);
while(queue.size() < height){
int currentLength = queue.size();
int i = 0;
while(i < currentLength){
int[] temp = queue.poll();
int[] array1 = new int[temp.length/2];
int[] array2 = new int[temp.length/2];
System.arraycopy(temp, 0, array1, 0, array1.length);
System.arraycopy(temp, array1.length, array2, 0, array2.length);
queue.add(array1); //I think the problem is here
queue.add(array2);
i++;
}
}
int y = 0;
while(y < 2){
for(int i = 0; i < queue.size(); i++){
int[] curr = queue.poll();
list.add(curr[y]);
queue.add(curr);
}
y++;
}
int[] ret = new int[list.size()];
for(int i = 0; i < list.size(); i++){
ret[i] =list.get(i);
}
return ret;
}
}
result:
1
3
5
7
2
4
6
8
how would I fix this?
update: I solved it and posted my own answer. but I am still curious as of how would other people solve this. Please stil feel free to answer.
I think the pattern becomes clear if you use 0-based indices
and express numbers in binary. e.g
0 1 2 3 4 5 6 7
000 001 010 011 100 101 110 111
0 1 2 3
000 001 010 011
100 101 110 111
4 5 6 7
0 = 000 001 = 1
4 = 100 101 = 5
2 = 010 011 = 3
6 = 110 111 = 7
0 = 000
4 = 100
2 = 010
6 = 110
1 = 001
5 = 101
3 = 011
7 = 111
see the pattern in the left-most bits? the sequence is just
the numbers 0,1,2 .. with the bit order reversed.
I solved it using two artillery queues and a main queue:
import java.util.*;
public class StackArray{
public static void main(String[] args){
int[] array = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
int[] answer = stackArray(array);
for(int n : answer){
System.out.println(n);
}
}
public static int[] stackArray(int[] array){
int height = (int) (Math.log(array.length)/Math.log(2)) + 1;
Queue<int[]> queue = new LinkedList<int[]>();
ArrayList<Integer> list = new ArrayList<>();
Queue<int[]> queue1 = new LinkedList<int[]>();
Queue<int[]> queue2 = new LinkedList<int[]>();
queue.add(array);
while(queue.size() < height){
int currentLength = queue.size();
int i = 0;
while(!queue.isEmpty()){
int[] temp = queue.poll();
int[] array1 = new int[temp.length/2];
int[] array2 = new int[temp.length/2];
System.arraycopy(temp, 0, array1, 0, array1.length);
System.arraycopy(temp, array1.length, array2, 0, array2.length);
queue1.add(array1); //I think the problem is here
queue2.add(array2);
i++;
}
while(!queue1.isEmpty()){
int[] temp1 = queue1.poll();
queue.add(temp1);
}
while(!queue2.isEmpty()){
int[] temp2 = queue2.poll();
queue.add(temp2);
}
}
int y = 0;
while(y < 2){
for(int i = 0; i < queue.size(); i++){
int[] curr = queue.poll();
list.add(curr[y]);
queue.add(curr);
}
y++;
}
int[] ret = new int[list.size()];
for(int i = 0; i < list.size(); i++){
ret[i] =list.get(i);
}
return ret;
}
}
output;
1
5
3
7
2
6
4
8
also test on when n = 4:
1
9
5
13
3
11
7
15
2
10
6
14
4
12
8
16

Count occurrence of integers in an array

I have an integer array: int[] numbers = new int[...n]; // n being limitless.
Where all the numbers are between 0 and 100.
Say numbers[] was equal to: [52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0];
I want to count how often each of those numbers occur.
I've got a second array: int[] occurrences = new int[100];.
I'd like to be able to store the amounts like such:
for(int i = 0; i < numbers.length; i++) {
// Store amount of 0's in numbers[] to occurrences[0]
// Store amount of 1's in numbers[] to occurrences[1]
}
So that occurrences[0] would be equal to 3, occurrences[1] would be equal to 0 etc.
Is there any efficient way of doing this without having to resort to external libraries? thanks.
You can simply do something like this:
for (int a : numbers) {
occurrences[a]++;
}
Also, if you mean 0 to 100 inclusive then occurrences will need to be of size 101 (i.e. 100 will need to be the maximum index).
You might also want to perform an "assertion" to ensure that each element of numbers is indeed in the valid range before you update occurrences.
Updated to put results in the 100-array.
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
<P>{#code java IntOccurancesInArray}</P>
**/
public class IntOccurancesInArray {
public static final void main(String[] igno_red) {
int[] ai = new int[]{52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0};
Map<Integer,Integer> mpNumWHits = new TreeMap<Integer,Integer>();
for(int i = 0; i < ai.length; i++) {
int iValue = ai[i];
if(!mpNumWHits.containsKey(iValue)) {
mpNumWHits.put(iValue, 1);
} else {
mpNumWHits.put(iValue, (mpNumWHits.get(iValue) + 1));
}
}
Set<Integer> stInts = mpNumWHits.keySet();
Iterator<Integer> itrInts = stInts.iterator();
int[] ai100 = new int[100];
int i = 0;
while(itrInts.hasNext()) {
int iValue = itrInts.next();
int iHits = mpNumWHits.get(iValue);
System.out.println(iValue + " found " + iHits + " times");
ai100[iValue] = iHits;
}
for(int j = 0; j < ai100.length; j++) {
if(ai100[j] > 0) {
System.out.println("ai100[" + j + "]=" + ai100[j]);
}
}
}
}
Output:
[C:\java_code\]java IntOccurancesInArray
0 found 3 times
2 found 1 times
3 found 1 times
5 found 1 times
12 found 1 times
21 found 1 times
32 found 2 times
43 found 1 times
52 found 1 times
67 found 1 times
ai100[0]=3
ai100[2]=1
ai100[3]=1
ai100[5]=1
ai100[12]=1
ai100[21]=1
ai100[32]=2
ai100[43]=1
ai100[52]=1
ai100[67]=1
This method is useful for knowing occurrences of all elements
You can reduce the space by finding the length of new array using sorting and taking value of last element + 1
import java.util.Arrays;
public class ArrayMain {
public static void main(String[] args) {
int a[] = {52, 67, 32, 43, 32, 21, 12, 5, 0, 3, 2, 0, 0};
Arrays.sort(a);
int len=a[a.length-1]+1;
int count[]=new int[len];
for(int n:a){
count[n]++;
}
for(int j=0;j<count.length;j++){
if(count[j]>=1){
System.out.println("count:"+j+"---"+count[j]);
}
}
}
}
Time Complexity : O(n)
Space Complexity : O(R) // last element value +1
Note : Creating new array may not be good idea if you have extreme numbers like 1, 2 and 96, 99 etc in terms of space.
For this case sorting and comparing next element is better approach
import java.util.Scanner;
public class CountNumOccurences {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int[] frequency = new int[100];
System.out.println("Enter the first integer: ");
int number = input.nextInt();
//Enter up to 100 integers, 0 to terminate
while (number != 0){
++frequency[number];
//read the next integer
System.out.print(
"Enter the next int value (zero to exit): ");
number = input.nextInt();
}
input.close();
System.out.println("Value\tFrequency");
for (int i = 0; i < frequency.length; i++) {
if (frequency[i] > 0){
if (frequency[i] > 1)
System.out.println(i + " occurs " + frequency[i] + " times");
else
System.out.println(i + " occurs " + frequency[i] + " time");
}
}
}
}

Categories