Dynamic programming problem -Minimum Cost Path - c++

I was trying this problem - Minimum Cost Path.
I have solved the problem using Dijkstra's Shortest Path Algorithm. But when i tried this using recursion+memoisation i.e. using dynamic programming, i got stuck and could not debug my code. I need help as to where my code is wrong!!
I am really glad for the help.
#include<bits/stdc++.h>
using namespace std;
int n;
int a[105][105], dp[105][105];
int dfs(int x, int y){
if(x < 0 || y < 0 || x >= n || y >= n){
return INT_MAX;
}
if(x == 0 && y== 0){
return a[0][0];
}
if(dp[x][y] != -1){
return dp[x][y];
}
dp[x][y] = a[x][y] + min(dfs(x-1, y), min(dfs(x, y-1), min(dfs(x+1, y), dfs(x, y+1))));
return dp[x][y];
}
int main(){
int tt;
cin >> tt;
while(tt--){
int n;
cin >> n;
for(int i = 0 ; i < n; i++){
for(int j = 0; j < n; j++){
cin >> a[i][j];
dp[i][j] = -1;
}
}
cout << dfs(n-1, n-1) << endl;
}
return 0;
}
Example:
Input:
2
5
31 100 65 12 18 10 13 47 157 6 100 113 174 11 33 88 124 41 20 140 99 32 111 41 20
2
42 93 7 14
Output:
327
63
I am getting 2147483647 as the output for both the cases, which is the value of INT_MAX.

The global variable n that dfs looks at is always zero (by static initialization), it's never assigned a value. When main calls, say, dfs(4, 4), the function immediately returns INT_MAX due to 4 >= 0 check.
Once you fix this simple issue, you'll discover that your program crashes due to stack overflow. You see, dfs(4, 4) calls dfs(3, 4), which in turn calls dfs(4, 4), which calls dfs(3, 4), which ...
This is not really a dynamic programming problem. It's a "shortest path in a graph" problem, suitable for, say, Dijkstra or A* algorithms.

Related

Kruskal algorithm, cycles and unvisited vertices

Algorithm does not pass through vertex 1(Z) and 4(B). Cycles are for vertices 12-13-14(S-T-K) and 13-15-16(T-L-R), how to fix it?
Below is the command, my code, graph, my output and the input file.
The input file contains the data of one connected graph. Its first line contains an integer Nv that specifies the number of edges of the graph. Then there are Nv lines containing descriptions of the consecutive vertices. The description of each node contains a positive integer corresponding to its identifier and a text string corresponding to its name. It can be assumed that both the number of vertices and the identifiers will not exceed 32,767, the length of the name will not be more than 8 characters, and it will only contain letters or numbers. The next line is the number Ne that specifies the number of edges in the graph. Then there are Ne lines containing the description of the subsequent edges. The description of each edge contains three positive integers, the first two correspond to the identifiers of the vertices connected by the given edge, the third is the weight of this edge.
The output should be exactly as many lines as the edges contain the Minimal Spanning Tree, each line should contain information about one edge. The information for each edge should contain the names of the vertices and the edge weight separated by spaces.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Vertex
{
int id;
char name[8];
};
struct Edges
{
int source;
int destination;
int weight;
};
void quickSort(Edges* tab, int left, int right)
{
if (right <= left)
{
return;
}
int i = left - 1, j = right + 1, pivot = tab[(left + right) / 2].weight;
while (1)
{
while (pivot > tab[++i].weight);
while (pivot < tab[--j].weight);
if (i <= j)
{
swap(tab[i].source, tab[j].source);
swap(tab[i].destination, tab[j].destination);
swap(tab[i].weight, tab[j].weight);
}
else
{
break;
}
}
if (j > left)
{
quickSort(tab, left, j);
}
if (i < right)
{
quickSort(tab, i, right);
}
}
int main()
{
int vertexnumber;
int edgenumber;
Edges* edgeList{};
vector<Edges> MST;
vector<Vertex> vertexList;
cin >> vertexnumber;
for (int i = 0; i < vertexnumber; i++)
{
vertexList.push_back(Vertex());
cin >> vertexList[i].id;
cin >> vertexList[i].name;
}
cin >> edgenumber;
edgeList = new Edges[edgenumber];
for (int i = 0; i < edgenumber; i++)
{
cin >> edgeList[i].source;
cin >> edgeList[i].destination;
cin >> edgeList[i].weight;
}
quickSort(edgeList, 0, edgenumber);
int iterator = 0;
for (int i = 0; i < edgenumber; i++)
{
bool isLoop = false;
int helper = edgeList[i].source;
for (int j = 0; j < MST.size(); j++)
{
for (int k = 0; k < MST.size(); k++)
{
if (MST[k].source == helper)
{
helper = MST[k].destination;
break;
}
if (MST[k].destination == helper)
{
helper = MST[k].source;
break;
}
}
if (edgeList[i].destination == helper)
{
isLoop = true;
break;
}
}
if (!isLoop)
{
MST.push_back(Edges());
MST[iterator].destination = edgeList[i].destination;
MST[iterator].source = edgeList[i].source;
MST[iterator].weight = edgeList[i].weight;
iterator++;
if (MST.size() >= vertexnumber - 1)
{
break;
}
}
}
for (int i = 0; i < MST.size(); i++)
{
for (int j = 0; j < vertexList.size(); j++)
{
if (vertexList[j].id == MST[i].source)
{
cout << vertexList[j].name << " ";
break;
}
}
for (int j = 0; j < vertexList.size(); j++)
{
if (vertexList[j].id == MST[i].destination)
{
cout << vertexList[j].name << " ";
break;
}
}
cout << MST[i].weight << endl;
}
}
S K 60
D O 82
O S 96
F P 108
T K 109
P C 110
W E 115
S T 124
E T 130
G N 135
T R 136
L R 138
F D 139
T L 142
G C 145
16
1 Z
2 G
3 N
4 B
5 F
6 P
7 C
8 W
9 E
10 D
11 O
12 S
13 T
14 K
15 L
16 R
34
1 2 288
1 5 175
1 6 192
2 3 135
2 6 246
2 7 145
3 4 188
3 7 177
3 8 174
4 8 179
4 15 213
5 6 108
5 10 139
6 7 110
6 9 187
6 10 147
6 11 203
7 8 218
7 9 172
8 9 115
8 13 146
8 15 153
9 11 168
9 12 174
9 13 130
10 11 82
11 12 96
12 13 124
12 14 60
13 14 109
13 15 142
13 16 136
14 16 148
15 16 138
There are at least two issues with your code:
When you call your quicksort implementation you should start it with edgenumber - 1 as right border index, otherwise you access uninitialised data.
Your loop detection is not correct because you don't care for the case where there are already three or more edges in MST with the same vertex. Here the path can split but you just follow one of them. Thus you add also cyclic edges to MST and the limit of MST.size() >= vertexnumber - 1 is reached before you could link all vertices to the tree.
I hope this helps. There are plenty of implementations in the net (e.g. see external links in the wikipedia article) where you can study how others have solved the task of loop detection. But if my assumption is right that you are doing this as homework, of course, it is better to try yourself.

Cannot give necessary input to C++ program in windows console

I'm trying to solve CSES Problem Set: Apartments, which have input like this in 3 lines, but I am unable to process/pass all three lines in the Windows terminal. I am using Geany editor and compilation is successful.
10 10 0
37 62 56 69 34 46 10 86 16 49
50 95 47 43 9 62 83 71 71 7
Can anyone review and tell me what is wrong? Is there fault in my logic?
#include <bits/stdc++.h>
using namespace std;
int n, m, k;
int main()
{
vector<int> v1;
vector<int> v2;
vector<bool> allotted(n, false);
cin >> n >> m >> k;
for (int i = 0; i < n; ++i) {
cin >> v1[i];
}
for (int j = 0; j < m; ++j) {
cin >> v2[j];
}
sort(v2.begin(), v2.end());
sort(v1.begin(), v1.end());
int ans = 0;
for (int req = 0; req < n; ++req) {
for (int x = -k; x <= k; ++x) {
if (find(v2.begin(), v2.end(), v1[req]+x) != v2.end() && alloted[req] == false) {
++ans;
allotted[req] = 1;
}
else {
continue;
}
}
}
cout << ans;
return 0;
}
Output:
10 10 0
37 62 56 69 34 46 10 86 16 49
------------------
(program exited with code: -1073741819)
You must allocate elements before accessing them or add elements via push_back.
To allocate elements, using resize() is one good way.
vector<int> v1;
vector<int> v2;
vector<bool> allotted(n, false); // note that n is zero here!
cin>>n>>m>>k; // after here, the size will be n (may not when the reading fails)
// allocate elements
v1.resize(n);
v2.resize(m);
allotted.resize(n);
You forgot to tell your vectors how long they should be. As a result you 're reading data into non-existing variables.
As an alternative to MikeCAT's answer, if you delay the declaration of your vectors until you know how big they need to be then you can create them at the correct size.
cin>>n>>m>>k;
vector<int> v1(n); // v1 has size n
vector<int> v2(m); // v2 has size m
vector<bool> allotted(n, false); // allotted has size n

Logical Error in given program cannot find it

In this problem we are given two arrays attackArray and defArray both of size N.
Now we think each array element to be a say, solider.
We need to output the particular element which is greater than its neighbours & greater than their sum. If multiple elements can the output then output the largest one.
-1 If no such element is found.
Custom input I tried to run it with
Input
4
4
1 1 4 1
3 4 2 1
7
5 4 5 4 5 4 5
3 2 4 7 2 5 9
3
5 8 1
5 6 20
20
46 35 17 37 39 48 10 49 44 11 36 4 2 22 16 41 26 8 15 40
4 41 6 35 49 50 28 46 22 17 13 36 31 2 33 14 150 47 29 39
Output
3
-1
20
-1
.Last output should've been 150.
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T;
if (T > 100 || T < 1)
return 0;
do {
vector<int> ans;
int N;
cin >> N;
if (N > 100 || N < 3)
return 0;
vector<long long int> attackArray(N), defArray(N);
for (int i = 0; i < N; i++) {
cin >> attackArray.at(i);
}
for (int i = 0; i < N; i++) {
cin >> defArray.at(i);
}
if (defArray.at(0) > attackArray.at(1) && defArray.at(0) > attackArray.at(N - 1) && defArray.at(0) > attackArray.at(1) + attackArray.at(N - 1)) {
ans.push_back(defArray.at(0));
}
if (defArray.at(N - 1) > attackArray.at(0) && defArray.at(N - 1) > attackArray.at(N - 2) && defArray.at(N - 1) > attackArray.at(0) + attackArray.at(N - 2)) {
ans.push_back(defArray.at(N - 1));
}
for (int i = 1; i < N - 1; i++) {
int nexti, previ;
nexti = i + 1;
previ = i - 1;
if (defArray.at(i) > attackArray.at(nexti) && defArray.at(i) > attackArray.at(previ) && defArray.at(i) > attackArray.at(nexti) + attackArray.at(previ)) {
ans.push_back(defArray.at(i));
}
else {
ans.push_back(-1);
break;
}
}
sort(ans.begin(), ans.end(), greater<int>());
cout << ans[0] << endl;
T--;
} while (T != 0);
return 0;
}
It works for the first line because the first element in defArray is larger than the attack of the neighbours so it doesn't need to enter the loop (you check specially for the first element).
It works for the third line because the last element in defArray is larger than the attack of the neighbours so it doesn't need to enter the loop (you check specially for the last element).
It doesn't work for any item in the loop after the first one because as soon as something in defArray is not larger than the attack of the neighbours you call break; and exit the loop. You need to check every element in defArray but the loop stops as soon as any element fails. Why are you calling break; anyway?
I haven't tested all the boundary conditions but removing the break; does seem to fix it...

What's wrong with 3n+1 program?

Here is my code for uva 3n+1 problem:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
ios_base::sync_with_stdio(false);
while(1){
long long n, n2, i, iConst, maximum;
vector<long long> vCycle;
cin >> n >> n2;
if(n < n2){
for(long long i = n; i <= n2; i++){
long long j = 1;
iConst = i;
while(iConst > 1){
if(iConst%2 == 0)
iConst = iConst / 2;
else
iConst = (iConst*3)+1;
j++;
}
vCycle.push_back(j);
}
}else{
for(long long i = n2; i <= n; i++){
long long j = 1;
iConst = i;
while(iConst > 1){
if(iConst%2 == 0)
iConst = iConst / 2;
else
iConst = (iConst*3)+1;
j++;
}
vCycle.push_back(j);
}
}
maximum = *max_element(vCycle.begin(), vCycle.end());
cout << n << " " << n2 << " " << maximum << endl;
}
return 0;
}
But the judge is giving the following error: "Time limit exceed".
Is there anything in my code which is using much CPU?
What's wrong with my program?
*Problem link: here
This is not the way, for few numbers it takes a lot of iterations to get the final output where they are already precalculated.
For Example
for n = 10,
10
5
16
8
4
2
1
for n = 20,
20
10
5
16
8
4
2
1
for n = 160,
160
80
40
20
10
5
16
8
4
2
1
Look at how many numbers are getting repeated, you already calculated the number of steps for 10, when calculating for n = 20, we need not calculate it again when n becomes 10 as we have done it already.
I suggest you to maintain a cache of calculated numbers and check each time if the value is pre-calculated, if yes just give the number + the existing count.
else do the math.
This is a Project Euler problem. Longest Collatz sequence is what it is called. They need more than code to solve them.
It is timing out because your algorithm is quite inefficient.
Just think of the test case given with the problem description -
22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
When you are generating the sequence for finding the answer for 22, you can also calculate the answers for every other number in the sequence.
int foo( int n )
{
if ( ans[n] has been calculated )
{
return ans[n]
}
if ( n is odd )
{
ans[n] = foo( 3n + 1 ) + 1
}
else
{
ans[n] = foo( n / 2 ) + 1
}
return ans[n]
}
where ans is an array of size 10^6.
As far as the task of finding the maximum between any 2 numbers is concerned, you can use a segment tree rather than simply finding the maximum element using a linear search

Modifing Arrays without using <algorithm> functions in C++? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So first, we start with an array of 50. The range of the values within the array can be 1-100, not repeating. Then we display the highest value of that random array. Then we display the lowest value in the array. Then comes the sorting, which would be easy using the standard library functions in the <algorithm> header, but since it's not allowed, we need to find another way around it. Then sort from high to low.
So, to display this easily... First we start with an array[50] with random numbers between 1-100
72 29 11 41 31 27 21 46 43 40 17 45 30 32 25 15 19 88 22 24 51 34 99 23 26 37 1 4 2 9 33 44 12 39 38 3 47 48 5 42 49 18 54 55 87 16 28 20 50 9
Now we display the highest number
99
Then the lowest
1
The we sort them
1 2 3 4 5 9 9 11 12 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 54 55 72 87 88 99
Then reverse sort them
99 88 87 72 55 54 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 12 11 9 9 5 4 3 2 1
So.. how would I go about doing this without algorithms?
The usual way to do this is by using loops.
For example, to traverse an array, printing every element, we could use a loop like:
for (int i=0; i<50; i++) {
std::cout << array[i] << std::endl;
}
All of the problems you mention, except sorting, can be done using a simple loop like the one above. You'll have to do your own bookkeeping in order to solve the problems, but it shouldn't be too difficult.
As for sorting, that's a more challenging problem. You might start with the wikipedia article to see how that is handled. You probably want to try implementing selection sort.
You can use bitset sort since the range of values of the array is limited to 1-100, and there is no repetition you can have a bitset array of 100 ints where each index specifies can be a 0 (that number isn't in the array) or a 1 (the number is in the array). For example the array [1, 5, 3] can be represented by the bitset array [1, 0, 1, 0, 1].
pseudo code:
MAX_SIZE = 100
bitset = new int[MAX_SIZE]
smallest = biggest = -1
for each value in array {
smallest = value if value < smallest
biggest = value if value > biggest
bitset[value-1] = 1
}
sorted = (i for i in 0..bitset.length - 1 if bitset[i] == 1)
reverse_sorted = (sorted[i] for i in sorted.length-1..0)
Not very professional but works
int array[50], used[50], sortedArray[50], buildSort = 1, genNum, max = 0, min = 101;
bool x;
srand(time(0));
//Array Generator
for(int i = 0; i < 50; i++){
do{
genNum = (1+rand()%100);
x = false;
for(int j =0; j < 50; j++){
if(genNum == used[j]){
x = true;
}
}
}while(x == true);
used[i] = genNum;
array[i] = genNum;
}
cout << "Numbers: ";
for(int d = 0; d < 50; d++){
cout << array[d] << " ";
}
cout << endl << endl;
//Max and Min finder
for(int m = 0; m < 50; m++){
if(array[m] > max){
max = array[m];
}
if(array[m] < min){
min = array[m];
}
}
cout << "Max is: " << max << endl;
cout << "Min is: " << min << endl << endl;
//Sorting
sortedArray[0] = min;
for(int v = min+1; v <= max; v++){
for(int r = 0; r < 50; r++){
if(array[r] == v){
sortedArray[buildSort] = array[r];
buildSort++;
}
}
}
cout << "Sorted: ";
for(int k = 0; k < 50; k++){
cout << sortedArray[k] << " ";
}
cout << endl << endl;
cout << "Reverse sorting: ";
for(int l = 49; l >=0; l--){
cout << sortedArray[l] << " ";
}
Well, I have not checked this code and I'm sure it has some errors in it, but hopefully this will at least give you some ideas and a good base to go off of:
/******************
*
* Your array should have 51 spots.
* The last element should be 0.
*
******************/
uint8_t findMax(uint8_t *arrayToSearch){
// Your array should end in a sentinel value of 0
uint8_t highest = 0;
for(; *arrayToSearch; arrayToSearch++){
highest = (*arrayToSearch > highest) ? *arrayToSearch : highest;
}
return highest;
}
uint8_t findMin(uint8_t *arrayToSearch){
// Your array should end in a sentinel value of 0
uint8_t lowest = 101;
for(; *arrayToSearch; arrayToSearch++){
lowest = (*arrayToSearch < lowest) ? *arrayToSearch : lowest;
}
return lowest;
}
void sortAscending(uint8_t *arrayToSearch){
// sort from low to high
// get count of array (According to your question, it should be 50, but we'll verify)
unsigned short count = 0;
uint8_t *countingPoint;
countingPoint = arrayToSeach; // make countingPoint point to the first element
while(*countingPoint){
count++;
countingPoint++;
}
// now we'll create a second array
uint8_t sortedArray[count];
// now let's begin sorting.
unsigned long int totalIterations = 0;
while(totalIterations < count){
uint8_t currentSmallest = 101; // value which will not ever exist.
signed long int smallestIndex = -1;
unsigned short offset = 0;
uint8_t *startOfArray;
startOfArray = arrayToSearch;
for(; *startOfArray; *startOfArray++, offset++){
if(currentSmallest > *startOfArray){
smallestIndex = offset;
currentSmallest = *startOfArray;
}
} /* end for */
sortedArray[totalIterations] = currentSmallest;
*(smallestIndex + arrayToSearch) = 101; /* set the value above 100 so it will be
skipped in the next for loop */
totalIterations++;
} /* end while */
/* now we'll the sorted values to the array to search */
int i;
for(i=0; i < count; i++){
*(i+arrayToSearch) = sortedArray[i];
}
// and we're done.
}
/*
* We can actually write sortDescending the same way and just modify
* the last loop to put them in reverse order
*/
void sortDescending(uint8_t *arrayToSearch){
// sort from low to high and then order as high to low
// get count of array (According to your question, it should be 50, but we'll verify)
unsigned short count = 0;
uint8_t *countingPoint;
countingPoint = arrayToSeach; // make countingPoint point to the first element
while(*countingPoint){
count++;
countingPoint++;
}
// now we'll create a second array
uint8_t sortedArray[count];
// now let's begin sorting.
unsigned long int totalIterations = 0;
while(totalIterations < count){
uint8_t currentSmallest = 101; // value which will not ever exist.
signed long int smallestIndex = -1;
unsigned short offset = 0;
uint8_t *startOfArray;
startOfArray = arrayToSearch;
for(; *startOfArray; *startOfArray++, offset++){
if(currentSmallest > *startOfArray){
smallestIndex = offset;
currentSmallest = *startOfArray;
}
} /* end for */
sortedArray[totalIterations] = currentSmallest;
*(smallestIndex + arrayToSearch) = 101; /* set the value above 100 so it will be
skipped in the next for loop */
totalIterations++;
} /* end while */
/* now we'll copy the values to the arrayToSearch in reverse order */
int i;
for(i=(count-1); i >= 0; i--){
*(i+arrayToSearch) = sortedArray[i];
}
// and we're done.
}
/* calling these */
int main(){
uint8_t yourArray[51];
// ... your code to populate this array
yourArray[50] = 0; // set the last spot to 0.
uint8_t highest = findMax(yourArray);
uint8_t lowest = findMin(yourArray);
// now make yourArray sorted by lowest to highest
sortAscending(yourArray);
// ... Whatever you need to do with it in ascending order.
// now make it sorted by highest to lowest
sortDescending(yourArray);
// ... Whatever you need to do with it in descending order.
return 0;
}
I'm a C-programmer so this is a rather C-style answer.
Some additional information that might be helpful can be found at:
http://www.sanfoundry.com/c-program-sort-array-ascending-order/
http://www.programmingsimplified.com/c/source-code/c-program-bubble-sort
http://en.wikipedia.org/wiki/Sorting_algorithm
The Wikipedia page (last link) might seem a little overwhelming, but there is a lot of great content on it.
I hope this will be of some help to you. Again, I'm not sure if the code I included will work properly. It's merely meant to convey the general idea.