How can I comapre two of the following objects? - c++

I'm trying to solve the 9-tile puzzle with the DFS/BFS (let's focus on the DFS as those two are basically the same) algorithm, and after some debugging I concluded why my code doesn't work.
I'm implementing the algorithm using a stack for the frontier, and a set for the closed set, and at some point I have to check if an object exists in the closed set. So naturally I use (temp is a 9-tile object):
if (closed.find(temp) == closed.end()){
\\do stuff
}
As I was trying to come out with this expression, I have learnt that I had to overload the '<' and '>' operators so that set.find() can work. So reaching my problem, the 9-tile objects are basically a 2d 3x3 array of integers, with
the value 0 where the empty tile is. How can I determine if, for example, one of the following states of my board are "greater" or "smaller" than the other?
6 7 1 3 6 0
0 3 2 2 8 4
4 5 6 5 1 7
I have tried comparing each element with the final state which is:
1 2 3
4 5 6
7 8 0
Adding one point for each tile that is the same as in the final but it doesn't work, obviously because two boards with completely incorrectly placed tiles will have the same score, so I cannot compare them.
I have also tried going through the elements of two boards, and composing scores like this:
bool operator < (const Board &A, const Board &B){
int scoreA=0, scoreB=0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
scoreA += i * j * A.getTile(i, j);
scoreB += i * j * B.getTile(i, j);
}
}
return scoreA < scoreB;
}
However I'm not positive that this is correct, as I don't get the results I want.
Can you propose a better method of comparing two boards like this?

You could try making an integer from the board such as
1 2 3
4 5 6 = 123456780
7 8 0
or in any pattern you'd like more.
This way, you don't have to compare the boards, only integer representations.

Since your variables which you compare are scores, I assume you want to do the comparison to check which board is closer to the solution of the tile moving problem.
In this case, you have to define some function double calculateScore(const Board& board) and then do a comparison:
double calculateScore(const Board& board)
{
double score = 0.0;
// as you wrote: adding one point for each tile that is the same as in the final
return score;
}
bool operator<(const Board& lhs, const Board& rhs)
{
return calculateScore(lhs) < calculateScore(rhs);
}
Your goal is then to take the board that maximizes that score.

Since you're using BFS/DFS, it doesn't matter which elements are 'greater' or 'less'. You just need the ordering to be consistent (if a < b and b < c, then a < c), and whenever two boards are different you need one to be less than the other.
A lexographic comparison of the tiles suffices. Something like this:
bool operator < (const Board &A, const Board &B){
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
int aTile = A.getTile(i,j);
int bTile = B.getTile(i,j);
if (aTile != bTile) {
return (aTile<bTile);
}
}
}
return false; //equal
}
Note that this will work just fine, but it will be faster to use unordered_set.
Also, since you'll be creating so many boards, it would be nice to use a smaller representation. If you pack them into an int as another poster suggest, then you can compare them with standard <. If you pack them into a byte array, you can use memcmp.

Related

How exactly can I handle the following condition while applying dijkstra's algorithm to this?

So, I was solving the following question: http://www.spoj.com/problems/ROADS/en/
N cities named with numbers 1 ... N are connected with one-way roads. Each road has two parameters associated with it: the road length and the toll that needs to be paid for the road (expressed in the number of coins). Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash. We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has.
Input
The input begins with the number t of test cases. Then t test cases follow. The first line of the each test case contains the integer K, 0 <= K <= 10000, maximum number of coins that Bob can spend on his way. The second line contains the integer N, 2 <= N <= 100, the total number of cities. The third line contains the integer R, 1 <= R <= 10000, the total number of roads. Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters : S is the source city, 1 <= S <= N D is the destination city, 1 <= D <= N L is the road length, 1 <= L <= 100. T is the toll (expressed in the number of coins), 0 <= T <= 100 Notice that different roads may have the same source and destination cities.
Output
For each test case, output a single line contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins. If such path does not exist, output -1.
Now, what I did was, I tried to use the djikstra's algorithm for this which is as follows:
Instead of only having a single node as the state, I take
node and coins as one state and then apply dijkstra.
length is the weight between the states.
and I minimize the length without exceeding the total coins.
My code is as follows:
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
class node
{
public:
int vertex;
int roadlength;
int toll;
};
int dist[101][101]; // for storing roadlength
bool visited[101][10001];
int cost[101][101]; // for storing cost
int ans[101][10001]; // actual distance being stored here
void djikstra(int totalcoins, int n);
bool operator < (node a, node b)
{
if (a.roadlength != b.roadlength)
return a.roadlength < b.roadlength;
else if (a.toll != b.toll)
return a.toll < b.toll;
return a.vertex < b.vertex;
}
int main (void)
{
int a,b,c,d;
int r,t,k,n,i,j;
cin>>t;
while (t != 0)
{
cin>>k>>n>>r;
for (i = 1; i <= 101; i++)
for (j = 1; j <= 101; j++)
dist[i][j] = INT_MAX;
for (i = 0; i <= n; i++)
for (j = 0; j <= k; j++)
ans[i][j] = INT_MAX;
for ( i = 0; i <= n; i++ )
for (j = 0; j <= k; j++ )
visited[i][j] = false;
for (i = 0; i < r; i++)
{
cin>>a>>b>>c>>d;
if (a != b)
{
dist[a][b] = c;
cost[a][b] = d;
}
}
djikstra(k,n);
int minlength = INT_MAX;
for (i = 1; i <= k; i++)
{
if (ans[n][i] < minlength)
minlength = ans[n][i];
}
if (minlength == INT_MAX)
cout<<"-1\n";
else
cout<<minlength<<"\n";
t--;
}
cout<<"\n";
return 0;
}
void djikstra(int totalcoins, int n)
{
set<node> myset;
myset.insert((node){1,0,0});
ans[1][0] = 0;
while (!myset.empty())
{
auto it = myset.begin();
myset.erase(it);
int curvertex = it->vertex;
int a = it->roadlength;
int b = it->toll;
if (visited[curvertex][b] == true)
continue;
else
{
visited[curvertex][b] = true;
for (int i = 1; i <= n; i++)
{
if (dist[curvertex][i] != INT_MAX)
{
int foo = b + cost[curvertex][i];
if (foo <= totalcoins)
{
if (ans[i][foo] >= ans[curvertex][b] + cost[curvertex][i])
{
ans[i][foo] = ans[curvertex][b] + cost[curvertex][i];
myset.insert((node){i,ans[i][foo],foo});
}
}
}
}
}
}
}
Now, I have two doubts:
Firstly, my output is not coming correct for the first given test case of the question, i.e.
Sample Input:
2
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
0
4
4
1 4 5 2
1 2 1 0
2 3 1 1
3 4 1 0
Sample Output:
11
-1
My output is coming out to be, 4 -1 which is wrong for the first test case. Where am I going wrong in this?
How do I handle the condition of having multiple edges? That is, question mentions, Notice that different roads may have the same source and destination cities. How do I handle this condition?
The simple way to store the roads is as a vector of vectors. For each origin city, you want to have a vector of all roads leading from that city.
So when you are processing a discovered "best" path to a city, you would iterate through all roads from that city to see if they might be "best" paths to some other city.
As before you have two interacting definitions of "best" than cannot be simply combined into one definition. Shortest is more important, so the main definition of "best" is shortest considering cheapest only in case of ties. But you also need the alternate definition of "best" considering only cheapest.
As I suggested for the other problem, you can sort on the main definition of "best" so you always process paths that are better in that definition before paths that are worse. Then you need to track the best seen so far for the second definition of "best" such that you only prune paths from processing when they are not better in the second definition from what you already processed prioritized by the first definition.
I haven't read your code, however I can tell you the problem cannot be solved with an unmodified version of Dijkstra's algorithm.
The problem is at least as hard as the binary knapsack problem. How? The idea is to construct the knapsack problem within the stated problem. Since the knapsack problem is known to be not solvable within polynomial time, neither is the stated problem's. Since Dijkstra's algorithm is a polynomial algorithm, it therefore could not apply.
Consider a binary knapsack problem with a set of D many values X and a maximum value m = max(X). Now construct the proposed problem as such:
Let there be D + 1 cities where city n is connected to city n + 1 by two roads. Let cities 1 through D uniquely correspond to a value v in X. Let only two roads from such a city n go only to city n + 1, one costing v with distance m - v + 1, and the other costing 0 with a distance of m + 1.
In essence, "you get exactly what you pay for" -- for every coin you spend, your trip will be one unit of distance shorter.
This reframes the problem to be "what's the maximum Bob can spend by only spending money either no or one time on each toll?" And that's the same as the binary knapsack problem we started with.
Hence, if we solve the stated problem, we also can solve the binary knapsack problem, and therefore the stated problem cannot be any more "efficient" to solve than the binary knapsack problem -- with Dijkstra's algorithm is.

How would one see if an array has consecutive numbers in C++?

This is basically the 8 Queens problem, but solving it with brute force in a 1D array. Say I have an array (named b) of size 8, with elements ranging from 0 to 7.
I initialize each index in the array with 8 for-loops, like this:
int b[8]={0};
int count = 0;
for(b[0] = 0; b[0]<8; b[0]++){
for(b[1] = 0; b[1]<8; b[1]++){
for(b[2] = 0; b[2]<8; b[2]++){
for(b[3] = 0; b[3]<8; b[3]++){
for(b[4] = 0; b[4]<8; b[4]++){
for(b[5] = 0; b[5]<8; b[5]++){
for(b[6] = 0; b[6]<8; b[6]++){
for(b[7] = 0; b[7]<8; b[7]++){
if(check(b))
{
count++;
print(b, count);
}
}}
}}
}}
}}
What this program is supposed to do is check every combination of numbers 0 to 7 and returning true for only certain conditions. There are supposed to be 92 solutions, if this sounds familiar, it should be - it is the 8 Queens problem using brute force. From here, this is what I understand are the conditions:
I want to be able to check if an array has a consecutive string of numbers; such as:
[0|5|7|1|2|3|6|4]
Here, the elements b[3], b[4] and b[5] are consecutive. I don't want that, I want to return false, since there is a consecutive string of numbers (basically queens are attacking)
I also do not want an array that has a string of backwards consecutive numbers like this:
[0|5|7|3|2|1|6|4]
And lastly, I do not want two or more numbers in indexes where it would make them look consecutive if we had simply changed then numbers between them:
[0|2|4|6|1|3|5|7]
Above is not acceptable because b[0] and b[7] are numbers in their "consecutive index" (because at least 2 queens are attacking each other).
[6|1|3|0|4|7|5|2]
Above is also not acceptable because b[1] and b[4] are also in consecutive indexes.
Similarly, when the values are swapped, the arrays
[7|2|4|6|1|3|5|0]
[6|4|3|0|1|7|5|2]
are also not acceptable. I also cannot have 2 or more of the same number.
The problem I am having is in creating the check function. I am told I need to use 1 for loop and 1 if-then statement. Can the check function just take the whole array as is? And if it does, how do look at the right-most element in the array, and check to see if it has consecutive indexes (queens are attacking it)? I've tried this:
bool ok(int board[8]){
for(int c = 7; c >= 0; c--){ //row check
for (int j=0; j<c; j++){
if (board[c]==board[j]){
return false;
}
}
for(int i = 1; i <= c; i++){
// diagonal check from top left to bottom right
if ((board[c]-i >= 0) && (board[c-i] == board[c]-i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]+i))
{return false;}
// diagonal check from bottom left to top right
if ((board[c]-i >= 0) && (board[c-i] == board[c]+i))
{return false;}
if ((board[c]+i <= 7) && (board[c+i] == board[c]-i))
{return false;}
}
}
return true;
}
But not only does this not work (I get 300+ solutions), it is not as small as I am told it should be.
I think there is a little problem with your check of collisions in the diagonals: you've got 15 diagonals going each way (including the very short one-square diagonals in the corners), while your code checks only seven of each due to the board[c]+i <= 7 and board[c]-i >= 0 conditions.
Here is how you can simplify the checks and make them faster with the use of three boolean arrays: you've got 8 rows, 15 ascending diagonals, and 15 descending diagonals:
bool row[8];
bool ascending[15];
bool descending[15];
Initially, there are no queens in any of these rows/diagonals. As you go through the elements of board, do this:
for (int i = 0 ; i != 8 ; i++) {
// Check and mark the row
if (row[board[i]]) return false;
row[board[i]] = true;
// Check and mark the ascending diagonal
int ascIdx = board[i]+i;
if (ascending[ascIdx]) return false;
ascending[ascIdx] = true;
int descIdx = 7+board[i]-i;
if (descending[descIdx]) return false;
descending[descIdx] = true;
}
return true;

Interesting algorithm to compare two matrices?

I have a problem, basically, I have two matrices (vectors), one massive matrix and a smaller matrix. I have an algorithm that splits the massive matrix into blocks (of the size of the small block)
So for example (I am using test data here) so the massive matrix size is: 4x4 and the small matrix is 2x2 and then I pass the particular block (at the current position) to a function that checks to see if the small matrix is equal to the massive block (at that particular position) if it is, then returns true otherwise returns false.
I can output each block like this:
bool compareMatrix(vector<double> &theMatrix1, vector<double> &theMatrix2, int startRow, int startCol)
{
// I can output the matrix blocks like this:
cout << theMatrix1[startRow*2+startCol] << endl;
}
But I don't quite understand how I would compare the block (at the startingRow/Col) to the small matrix..
How it would is this:
Matrix 1: (4x4)
0 1 0 1
1 1 0 1
0 0 1 1
0 1 1 1
Matrix 2: (2x2)
0 1
0 1
I then split the blocks into 2x2:
B1 =
0 1
1 1
is B1 equal to theMatrix2 - No so return false
B2 =
0 1
0 1
is B2 equal to theMatrix2 - Yes so return true
I have really tried to explain things to the best of detail as I possibly can and hope someone can give me some advice because I've been working on it for so long now!
Thanks
If the size of the big matrix is known you can compare small parts of it with your 2x2 matrix like so
int bigMatrixSize=4;
bool compare(...)
{
for (int i=0; i<2; ++i)
for (int k=0; k<2; ++k)
if(bigMatrix[k+startX+(i+staryY)*bigMatrixSize] != smallMatrix[k][i])
return false;
return true;
}
I left out bounds checking and some other stuff, but It should give you an idea.
bool compareMatrix(vector<double> &theMatrix1, int nRow1, int nCol1, vector<double> &theMatrix2, int nRow2, int nCol2, int startRow, int startCol)
{
int p1 = startRow * nCol1 + startCol, p2 = 0;
for (int y = 0; y < nRow2; ++y)
{
for (int x = 0; x < nCol2; ++x)
{
if (theMatrix1[p1 + x] != theMattrix2[p2 + x]) // You can use memcmp here, but it's safer let compiler do the optimization.
{
return false;
}
}
p1 += nCol1;
p2 += nCol2;
}
return true;
}
You want something like this? You can add the columns count to the position to reach the next row.

Splitting a massive matrix into blocks

I have a problem. I'm working on a task that tries to find a matrix (vector) inside another matrix(vector) and the size of the matrices are:
Massive Matrix: 1024x768
Small Matrix: 36x49
Basically, my theory was to split the massive matrix into blocks that were the size of the small matrix thus meaning I was able to just see whether the small matrix exists in which block and then output the block. However, it just will not split equally but I need a way to determine if the small matrix does actually exist in the massive matrix.
As an example, I'll use test data:
M1 =
0 1 0 0
1 1 1 1
0 0 0 0
1 0 1 1
M2 =
0 1
1 1
And then I would split the matrices into blocks of 2x2 and then check that way. This is simple as I'm only working with a small matrix AND the matrix can be split equally, whereas the problem above is a lot more complex to understand and figure out.
In essence, I need to be able to split the (1024x768) into block sizes of (36x49) so then I can do the check to determine where that particular matrix is. I have been working with this algorithm:
// Assume:
// matrix1ColSize = 768
// matrix2ColSize = 49
const int ROW_BOUNDS = matrix1.size() - matrix2.size();
const int COL_BOUNDS = matrix1ColSize - matrix2ColSize;
bool found = false;
for(int i=0; (i < ROW_BOUNDS); i++)
{
bool matchFound = false;
for(int j=0; (j < COL_BOUNDS); j++) {
// logic here
}
cout << endl;
}
Could anyone offer any advice please? This is really annoying me now :(!
Two matrices are the same if all their elements are the same. So the following pseudo-code compares the small matrix with a block in the large matrix:
Initialize result to "true"
For each position in the small matrix
Read the value from the large matrix; call it x1
Read the value from the small matrix; call it x2
If x1 is not equal to x2, set result to "false"
(Optional) If x1 is not equal to x2, stop looking at other positions
Here, use the result
This logic is going to be inside your 2 nested loops, so you will have 4 nested loops there! If you fear of getting confused, put the implementation inside a function. If you want to use 4 nested loops, good luck.
In c++:
bool is_equal = true;
for (int y = 0; y < 49; ++y)
{
for (int x = 0; x < 36; ++x)
{
if (matrix1.at(j + x, i + y) != matrix2.at(x, y))
{
is_equal = false;
goto DONE; // optional
}
}
}
DONE:;
Edit: this code assumes using a custom class for matrices; after looking again at your code i realize that you probably use a vector of vectors (std::vector<std::vector<int>>), so use matrix2[y][x] instead of matrix2.at(x, y).

diagonally reflect a matrix

I'm not sure if this question has been either asked
or quite possibly already answered. If I start with
an original 3x3 matrix:
1 2 3
4 5 6
7 8 9
, how would I produce the following 3x3 matrix:
9 6 3
8 5 2
7 4 1
??
For an N*N square matrix :
for(int i=0;i<n-1;i++)
for(int j=0;j<n-1-i;j++) //Swap elements above anti-diagonal
std::swap(mat[i][j],mat[n-1-j][n-1-i]); //with elements below it
Since you're trying to reflect about the secondary diagonal (that's NOT transposition), here's the code, a slightly modified copy of Peter's:
for (int i = 0; i < n; i++)
{
for (int j = 0; j < i; j++)
{
int temp = a[i][j];
a[i][j] = a[n - 1 - j][n - 1 - i];
a[n - 1 - j][n - 1 - i] = temp;
}
}
For a reflection, pairs of items in the matrix are swapped, so the "do something" (within the loops) will be a swap operation. Loops will be used to pick an item to swap, and some basic arithmetic is used to choose which item to swap it with. The loops should iterate over the triangle of items that are one side of the axis to reflect around, excluding those on the reflection axis and on the other side of it. To visualise that...
0 1 2
0 * * /
1 * / .
2 / . .
The asterisks are the items to use as first parameters for the swap. The dots are the items to use as second parameters to the swap. The slashes are on the reflection axis.
Therefore...
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < (n-1)-i; j++) // Thanks to Bugaboo for bugfix
{
std::swap (a[i][j], a[2-j][2-i]);
}
}
With a 3x3 matrix, the loops are a bit excessive - they are shown here for the principle, and to show how to extend it. There are only three asterisks in that visualisation, and only three swap operations needed...
std::swap (a[0][0], a[2][2]);
std::swap (a[0][1], a[1][2]);
std::swap (a[1][0], a[2][1]);
I think I found a way in the MatLab that combines a series of other existing flipping method.
fliplr (flip left and right)
transpose
fliplr
Ham is the target then the code is the following.
Maybe it is wrong, but let me know.
fliplr(fliplr(Ham)')