Applying heuristic to recursive backtracking - c++

Searched for other problems -- and there are similar ones, but none that deal with this particular heuristic.
I have working code for a problem which asks to take a vector into some function, determine whether any values in that vector sum up to a given target value, and then returns whether it does or not (boolean). This is simple.
I have to use the backtracking heuristic supplied to create this function (below), which is working correctly in principle. I have to ensure that my function is not generating combinations which have been generated before (ABC is the same as BAC, for instance). How do I prevent my code from doing this? I cannot change the parameters going into the function (so the function prototype has to remain as it is below), but wrapper or helper functions are OK.
Here is the heuristic:
bool Solve(configuration conf) {
if (no more choices) // BASE CASE
return (conf is goal state);
for (all available choices) {
try one choice c;
// recursively solve after making choice
ok = Solve(conf with choice c made);
if (ok) return true;
else unmake choice c;
}
return false; // tried all choices, no soln found
}
My code:
bool CanMakeSum(Vector<int> & nums, int targetSum) {
if (nums.isEmpty()) {
cout << "you've reached the target sum" << endl;
return true;
} else {
for (int i = 0; i < nums.size(); i++) {
element = nums[i];
Vector<int> rest = nums;
cout << "list the subset: " << listSubset(rest) << endl;
rest.removeAt(i);
// try one
int new_target_sum = targetSum - element;
CanMakeSum(rest, new_target_sum);
if (new_target_sum == 0) {
return true;
} else {
new_target_sum = targetSum + element;
}
}
}
return false;
}
string listSubset(Vector<int> &partial_solution) {
string solution = " ";
for (int i = 0; i < partial_solution.size(); i++) {
solution += IntegerToString(partial_solution[i]) + " ";
}
return solution;
}

You could introduce ordering in choosing elements. For example after choosing ith element you cannot choose any element with index less than i. Change required in code is that after choosing ith element you need to remove all elements from index 0 to i.

Related

Find indexes of duplicated (repeated) numbers in an array

I have 2 arrays in which arr1 stores a number (the salary) and arr2 stores a string (the employee's name). Since the two arrays are linked, I cannot change the order of arr1, or sort it. I am looking for a more efficient way to solve the problem which is to find if there are any duplicates in the array. It might be more than one duplicate, but if no are found it should print "no duplicates found".
int count = 0;
for (int i = 0;i<arr_size ;i++)
{
for (int j = 0; j < arr_size && i != j; j++)
{
if (arr[i] == arr[j])
{
cout << arr2[i] << " " << arr1[i] << endl;
cout << arr2[j] << " " << arr1[j] << endl;
count ++;
}
}
}
if (count == 0)
{
cout << "No employee have same salaries"<<endl;
}
I don't want to use such an inefficient way to solve the problem. Is there any better suggestion? Thanks for the help :)
And the question also requires me to print out all the duplicated employee and salaries pair
You can use an unordered_set which has an average constant time insertion and retrieval:
#include <unordered_set>
// ...set up arr
int count = 0;
std::unordered_set<int> salaries;
for (int i = 0; i < arr_size; i ++) {
if (salaries.count(arr[i]) > 0) {
// it's a duplicate
}
salaries.insert(arr[i]);
}
// do more stuff
Create a Haspmap using unordered_map and store salaries and index of the salary .
Now if the same salary exist then increase count
You can reduce the time complexity of the algorithm to O(n) by using unordered_set on the expense of using additional space.
#include<unordered_set>
int main(){
// Initialise your arrays
unordered_set<string> unique;
bool flag = false;
for(int i=0;i<arr_size;i++){
// Since unordered_set does not support pair out of the box, we will convert the pair to string and use as a key
string key = to_string(arr1[i]) + arr2[i];
// Check if key exists in set
if(unique.find(key)!=unique.end())
unique.push(key);
else{
// mark that duplicate found
flag = true;
// Print the duplicate
cout<<"Duplicate: "+to_string(arr1[i])+"-"+arr2[i]<<endl;
}
}
if(!flag){
cout<<"No duplicates found"<<endl;
} else cout<<"Duplicates found"<<endl;
return 0;
}

My array is gettting an error because it's being defined as a singular integer

The point of this program is to output whether a series of digits (the number of digits undefined) is sorted or not (largest to smallest or smallest to largest).
I have defined my array in my function parameter, and I am trying to use a for loop to store the user's input, as long as it is above 0, in said array.
However, I am getting the error argument of type int is incompatible with parameter of type int*.
The exact error is the argument of type int is incompatible with parameter of type int*.
It is referring to line 22 and 23, these two;
isSorted(list[2000]); and
bool is = isSorted(list[2000]);.
I know this means my for loop is assigning a single value to my variable repeatedly from reading similar questions however I can not figure out how to fix this.
#include <iostream>
using namespace std;
bool isSorted(int list[]);
int main()
{
int i;
int list[2000];
int k = 0;
for (i = 0; i < 2000; i++)
{
int j;
while (j > 0)
{
cin >> j;
list[i] = j;
}
}
isSorted(list[2000]);
bool is = isSorted(list[2000]);
if (is == true)
cout << "sorted";
else
cout << "unsorted";
return 0;
}
bool isSorted(int list[])
{
int i = 0;
for (i = 0; i < 2000; i++)
{
if (list[i] > list[i + 1] || list[i] < list[i - 1])
{
return false;
}
else
return true;
}
}
I removed unused variable k.
Made 2000 parameterized (and set to 5 for testing).
In isSorted you are not allowed to return
true in the else as if your first element test would end in else you would return true immediately not testing other elements. But those later elements can be unsorted as well.
In isSorted you are not allowed to run the loop as for(i = 0; i < 2000; i++), because you add inside the for loop 1 to i and end up querying for i == 1999 list[2000], which is element number 2001 and not inside your array. This is correct instead: for (i = 0; i < 1999; i++). You also do not need to check into both directions.
You cannot call isSorted(list[2000]) as this would call is sorted with an int and not an int array as parameter.
You write int j without initializing it and then query while j > 0 before you cin << j. This is undefined behaviour, while most likely j will be zero, there is no guarantee. But most likely you never enter the while loop and never do cin
I renamed the isSorted as you just check in your example for ascending order. If you want to check for descending order you are welcome to train your programming skills and implementing this yourself.
Here is the code with the fixes:
#include <iostream>
using namespace std;
bool isSortedInAscendingOrder(int list[]);
const int size = 5; // Set this to 2000 again if you want
int main()
{
int i;
int list[size];
for (i = 0; i < size; i++)
{
int j = 0;
while(j <= 0)
{
cin >> j;
if(j <= 0)
cout << "rejected as equal or smaller zero" << endl;
}
list[i] = j;
}
if (isSortedInAscendingOrder(list))
cout << "sorted" << endl;
else
cout << "unsorted" << endl;
return 0;
}
bool isSortedInAscendingOrder(int list[])
{
for (int i = 0; i < size -1; i++)
{
if (list[i] > list[i + 1])
{
return false;
}
}
return true;
}
This is a definition of an array of 2000 integers.
int list[2000];
This is reading the 2000th entry in that array and undefined, because the highest legal index to access is 1999. Remember that the first legal index is 0.
list[2000]
So yes, from point of view of the compiler, the following only gives a single integer on top of being undefined behaviour (i.e. "evil").
isSorted(list[2000]);
You probably should change to this, in order to fix the immediate problem - and get quite close to what you probably want. It names the whole array as parameter. It will decay to a pointer to int (among other things loosing the information of size, but you hardcoded that inside the function; better change that by the way).
isSorted(list);
Delete the ignored first occurence (the one alone on a line), keep the second (the one assigning to a bool variable).
On the other hand, the logic of a your sorting check is flawed, it will often access outside the array, for indexes 0 and 1999. I.e. at the start and end of your loop. You need to loop over slightly less than the whole array and only use one of the two conditions.
I.e. do
for (i = 1; i < 2000; i++)
{
if (list[i] < list[i - 1])
/* ... */
The logic for checking ascending or descending sorting would have to be more complex. The question is not asking to fix that logic, so I stick with fixing the issues according to the original version (which did not mention two-way-sorting).
You actually did not ask about fixing the logic for that. But here is a hint:
Either use two loops, which you can break from as soon as you find a conflict, but do not return from the fuction immediatly.
Or use one loop and keep a flag of whether ascending or descending order has been broken. Then return true if either flag is still clear (or both, in case of all identical values) or return false if both are set.

Using struct with an insertion sort

I'm having some trouble with an insertion sort, passing in data from a struct.
It's returning the error: |98| cannot convert 'store' to 'int' in assignment.
struct store{
char tag[5];
int cost;
long int volume;
};
void costSort(store storedEntries[], int count);
void volumeSort(store storedEntries[], int count);
int main(){
store record[100];
ifstream fin;
char choice;
int count = 0;
fin.open("stockdata.txt");
//file read in
if(fin.good())
{
while(!fin.eof())
{
fin >> record[count].tag;
fin >> record[count].cost;
fin >> record[count].volume;
count++;
}
count--;
}
cout << "Main Menu:" << endl;
cout << "c: sort data by Cost\nv: sort data by trade Volume\nq: Quit\nEnter Choice: ";
cin >> choice;
switch(choice)
{
case 'C':
case 'c': //costSort(record, count);
break;
case 'V':
case 'v': volumeSort(record, count);
break;
case 'q':
case 'Q': return 0;
break;
}
return 0;
}
void volumeSort(store record[], int count)
{
int p = 0, item = 0;
for(int i=1; i<count; i++){
cout << "test";
item = record[i];
p = (i - 1);
while(p>=0 && item < record[p]){
record[p+1] = record[p];
p--;
}
record[p+1] = item;
cout << record[i].tag << " " << record[i].volume << endl;
}
}
The insertion sort is in the function void volumeSort().
Any advice would be appreciated, i haven't had any issues up until now :S
You're comparing non-like types with no operator provided to support the comparison (and none needed if this is done correctly). Currently you're comparing int to store. What you should be comparing is two volume members of two store objects.
A simple loop that is probably closer to what you want would be something like this:
// note: count is size_t, an unsigned magnitude. only used signed
// integer types where it makes sense a negative integer will be
// plausible input.
void volumeSort(store record[], size_t count)
{
for(size_t i=1; i<count; ++i)
{
// compare current element to one below us, swapping if needed
// and stopping as soon as we reach an equal or lesser record
size_t j=i;
while(j>0 && record[j].volume < record[j-1].volume)
{
std::swap(record[j-1], record[j]);
--j;
}
}
}
Or something similar. Note the comparison of:
record[j].volume < record[j-1].volume
in the while condition. Apples to apples...
For an interesting insertion_sort that utilizes two wonderful features of the standard library, std::upper_bound and std::rotate, a rather dense version of the function can be created, looking something like this:
void insertion_sort(store record[], size_t len)
{
for (auto it = record; it != record+len; ++it)
{
std::rotate(std::upper_bound(record, it, *it,
[](const store& lhs, const store& rhs) { return lhs.volume < rhs.volume; }),
it, std::next(it));
}
}
This is considerably more efficient than it first may seem, as the search for the proper placement of the prospect element is done in O(logN) using std::upper_bound. Then std::rotate opens the hole where the element goes and it is swapped into place.
Just some food for thought. Coupled with the comparator that is going to inlined by even remedial optimization and it has a lot more punch than you may first think. Still not as kick-ass as std::sort, usually highly optimized utilizing multiple algorithms, but still good brain food.
Best of luck.
You are trying to compare a int with a store.
This will not work unless you overload < operator to compare a int and a store.
store record[];
int p = 0, item = 0;
//[...]
while (p >= 0 && item < record[p])
//Neither can you assign that
record[p + 1] = item;
Operator example:
bool operator<(const int &left, const store &s)
{
//You could also do some calculation in here,
//if you want to compare a value inside the struct
//like this:
return left < s.cost;
//Please... do it in place.
//item < record[p].cost;
}
if you want to sort by volume you should take
record[i].volume even when comparing...the types should be same when comparing values..
Similarly for other cases..

Getting an array of structures by using an element of structure

I have an array which holds a structure like:
struct Point
{
int x;
int y;
}
Point array_of_structure[10] ;
for(int i=0;i<10;i++)
{
array_of_structure[i].x = i*2;
}
I want to get the structure which holds x value of 6. In this way I access the y value of that structure. How can I do it?
It's something like the below:
Point p = Get the structure which contains x value of 6;
int c = p.y;
Here is a sample solution. But I need a better idea or ideas.
for(int i=0;i<10;i++)
if(array_of_structure[i].x==6)
return array_of_structure[i].y;
I thought about maybe pointers make this job but I'm not sure about it. I cannot figure out how to solve this problem.
Standard library provides a function std::find_if which can be used to find an item without a loop. As a learning exercise, however, you could do it using a loop as described below:
You can iterate your array of structs until you find the x of interest. You can use a pointer or an index, depending on your preferences. You need to set a flag indicating if you have found your item or not.
Here is how you can do it with a pointer:
struct Point *ptr;
bool found = false;
for (ptr = array_of_structure ; !found && ptr != &array_of_structure[10] ; ptr++) {
found = (ptr->x == x);
}
if (found) {
cout << ptr->y << endl;
}
Here is how you can do it with an index:
int index ;
bool found = false;
for (index = 0 ; !found && index != 10 ; index++) {
found = (array_of_structure[index].x == x);
}
if (found) {
cout << array_of_structure[index].y << endl;
}
Note: if you are looking for a find_if solution, here is an answer that explains this approach.

Why this Dijkstra (graph) implementation isn't working?

I made this implementation for this problem :
http://www.spoj.pl/problems/SHOP/
#include<iostream>
#include<stdio.h>
#include<queue>
#include<conio.h>
#include<string.h>
using namespace std;
struct node
{
int x;
int y;
int time;
};
bool operator <(const node &s,const node &r)
{
if(s.time>r.time)
return true;
else return false;
}
node beg,src,dest,tempa;
int b,a,temp;
int map[25][25];
bool vis[25][25];
int X[]={1,0,-1,0};
int Y[]={0,1,0,-1};
int djs_bfs(node src,node dest)
{
int result=0;
priority_queue<node>pq;
pq.push(src);
while(!pq.empty())
{
node top = pq.top();
pq.pop();
if(top.x==dest.x && top.y==dest.y) return result;
if(top.x<0 || top.x>=a) continue;
if(top.y<0 || top.y>=b) continue;
if(vis[top.x][top.y]) continue;
vis[top.x][top.y]=true;
result+=map[top.x][top.y];
for(int i=0;i<4;i++)
{
tempa.x=top.x+X[0];
tempa.y=top.y+Y[0];
tempa.time=map[top.x+X[0]][top.y+Y[0]];
pq.push(tempa);
}
}
return -1;
}
int main()
{
memset(vis,false,sizeof(vis));
scanf("%d %d",&a,&b);
while(a != 0)
{
for(int i=0;i<a;i++)
for(int j=0;j<b;j++)
{
scanf("%c",&temp);
if(temp=='X') {map[i][j]=0;vis[i][j]=true;}
if(temp=='S') {src.x=i;src.y=j;src.time=0;}
if(temp=='D') {dest.x=i;dest.y=j;dest.time=0;}
else map[i][j]=temp-'0';
}
cout<<djs_bfs(src,dest)<<endl;
scanf("%d %d",&a,&b);
}
return 0;
getch();
}
I don't know why my code doesn't generate the right answer for the testcases.
If someone can help me improve the code, please do so :D
First of all, the graph parsing code is incorrect. The first line specifies width and height, where the width is the number of characters per line the height is the number of lines. Therefore, swap &a and &b in the first scanf, or swap the order of the nested for loops (but not both). Also, I had to add dummy scanf("%c", &dummy); calls at various places to filter out newlines. A simple dump, such as this, will help determine if your map was parsed correctly:
cout << "a=" << a << endl;
cout << "b=" << b << endl;
for (int i=0; i<a; i++) {
for(int j=0; j<b; j++) {
cout << (char)('0' + map[i][j]) << ",";
}
cout << endl;
}
Note: I also set map[i][j] to 0 for 'S' and 'D', also changing the repeated if statements into an if; else if; else chain. This makes the algorithm more robust, since you can generically add time from the source or destination.
Now, on to the algorithm itself....
Each loop of the algorithm increments result by the current map location weight. However, the algorithm is searching multiple paths simultaneously (i.e., the number of entries in the priority queue), and therefore result ends up being the sum of all processed node weights, not the current path weight. The current path weight is top.temp, and therefore you can eliminate the result variable and simply return top.temp when you reach the destination.
Also, as other answers noted, you need to use X[i] and Y[i] in your inner loop, otherwise you are only searching in one direction.
Now, because of the addition/subtraction from X[i] and Y[i], you will likely access map[][] out of range (-1 or 25). Therefore, I recommend moving the if guards to the inner for loop to guard against the out-of-range access. This also avoids filling the priority queue with illegal possibilities.
Here is my version of the algorithm, with minimal corrections, for reference:
priority_queue<node>pq;
pq.push(src);
while(!pq.empty())
{
node top = pq.top();
pq.pop();
if(top.x==dest.x && top.y==dest.y) return top.time;
if(vis[top.x][top.y]) continue;
vis[top.x][top.y]=true;
for(int i=0;i<4;i++)
{
tempa.x=top.x+X[i];
tempa.y=top.y+Y[i];
if(tempa.x<0 || tempa.x>=a) continue;
if(tempa.y<0 || tempa.y>=b) continue;
tempa.time=top.time + map[tempa.x][tempa.y];
pq.push(tempa);
}
}
return -1;
I hope this helps.
Why do you have 0 indexes?
tempa.x=top.x+X[0];
tempa.y=top.y+Y[0];
tempa.time=map[top.x+X[0]][top.y+Y[0]];
Nitpick:
bool operator <(const node &s,const node &r)
{
if(s.time>r.time)
return true;
else return false;
}
Isn't this more readable:
bool operator <(const node &s,const node &r)
{
return (s.time>r.time);
}
You're using X[0] and Y[0] instead of X[i] and Y[i] in that inner loop.
By the way, other than that your Dijkstra's is very inefficient. First, you're pushing nodes onto the queue even when they have already been visited, and secondly, you may have several of the same node in the queue, just with different times. Ultimately neither of these things effect the outcome, but you're changing the complexity.
Edit: Oh, tempa.time should equal top.time plus the edge weight, not just the edge weight.