Google Kickstart Round C: Stable Wall, Wrong Answer - c++

This is the link to the problem here
We have to tell the order in which the letters(like bricks) have to be laid in order for the wall to be stable. ie; for example if the input is
ZOAAMM
ZOAOMM
ZOOOOM
ZZZZOM
Then if I lay 'A's first then they will fall to the ground since in order to lay the letter 'A' I need to lay the letters 'Z' and 'O' first.
If I lay all O's first then they will also fall on the ground since some of the O's depend on the 'Z' below to be laid first.
The answer for the above is 'ZOMA' or 'ZOAM' both are valid answers. If it's not possible then we should print -1.
What I did in my code is that I first made a graph. For the example above, the graph will be O-> A since A depends on O. O->M since M also depends on O. Z->O since O depends on Z.
Then if there is a cycle in the graph then that means it is not possible to lay the wall so I print -1
If there is no cycle then the answer exists, and to get the answer I do a topological sort.
All the example test cases passed, but when I submit, I get a wrong answer. I don't know which test case could be failing. Can you let me know any case which my code is failing for please.
#include<bits/stdc++.h>
using namespace std;
vector<int>adj[26]; // adjacency list to store the graph
int n,m; // n rows each with a string of size m
string s[30];
bool vis[26]; //for topological sort
int visited[26];//for cycle detection
stack <char> mystack;
bool flag = 0;
void cycledfs(int node) // returns -1 if cycle detected
{
if(visited[node] == -1)
{
flag = 1;
return;
}
visited[node] = -1;
for(int i = 0; i < adj[node].size(); i++)
{
if(visited[adj[node][i]] != 1)
{
cycledfs(adj[node][i]);
}
}
visited[node] = 1;
}
void dfs(int node) // if cycle is not detected we do the topological sorting
{
if(!vis[node])
{
vis[node] = 1;
for(int i = 0; i < adj[node].size(); i++)
{
if(!vis[adj[node][i]])
dfs(adj[node][i]);
}
mystack.push(node+'A');
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
set <char> t; // set to store all the unique letters which are my vertices of the graph
for(int i = 0; i <n; i++)
{
cin>>s[i];
for(int j = 0; s[i][j]!='\0';j++)
t.insert(s[i][j]);
if(i)
{
for(int j = 0; s[i][j]!='\0';j++)//to check if the brick above me is different from me. Also making sure no duplicates in the graph.
{
auto it = find(adj[s[i][j]-'A'].begin(), adj[s[i][j]-'A'].end(), (s[i-1][j]-'A'));
if(((s[i][j]-'A') != (s[i-1][j]-'A')) &&(it==adj[s[i][j]-'A'].end()))
adj[s[i][j]-'A'].push_back((s[i-1][j]-'A'));
}
}
}
//initializing stuff
flag = 0;
memset(visited, 0, sizeof(visited));
memset(vis, 0, sizeof(vis));
for(char i: t)//CYCLE CHECKING
{
//cout<<(i-'A')<<"\n";
if(visited[i-'A'] == 0)
cycledfs(i-'A');
if(flag)
break;
}
if(flag)
cout<<"-1\n";
else //doing topological sort if no cycle
{
string result ="";
for(char x: t)
dfs(x-'A');
while(!mystack.empty())
{
char ans = mystack.top();
result.push_back(ans);
mystack.pop();
}
cout<<result<<"\n";
}
for(int i = 0; i < 26; i++) //clearing adj list
adj[i].clear();
}
}

Related

Shortest path in an unweighted graph, using user input in C++

As I was practicing C++ today, I came across a code which finds the shortest path in an unweighted graph using BFS and outputs the length of the path and the vertices it travelled through.
I attempted to change up this code by introducing user input.
First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges.
The next M lines contain two integers, which indicates an undirected edge between two nodes.
I attempted to change the code in accordance to this, but I ran into a number of problems.
The first problem is that if I use gcc, the program will end after the for loop runs once in the main function.
However, if I use clang, the program runs fine. But there is an other issue and it relates to a very specific input.
The following input:
3 3
1 3
1 2
2 3
should return 1, but sometimes (specifically when I enter the input line by line) it returns the message: "Given source and destination are not connected". It is completely random.
The code is below:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[]);
void printShortestDistance(vector<int> adjList[], int s, int dest, int numOfVertices);
int main()
{
int numOfVertices, numOfEdges;
cin >> numOfVertices >> numOfEdges;
vector<int> adjList[numOfVertices];
if (2 <= numOfVertices && numOfVertices <= 1e5 && 1 <= numOfEdges && numOfEdges <= 1e5)
{
for (int i = 0; i < numOfEdges; i++)
{
int node1, node2;
cin >> node1 >> node2;
if ((1 <= node1) && (1 <= node2) && (node1 <= numOfVertices) && (node2 <= numOfVertices) && (node1 != node2))
{
adjList[node1].push_back(node2);
adjList[node2].push_back(node1);
}
else{ return EXIT_FAILURE; }
}
int source = 1;
int dest = numOfVertices;
printShortestDistance(adjList, source, dest, numOfVertices);
}
}
void printShortestDistance(vector<int> adjList[], int source, int dest, int numOfVertices)
{
int pred[numOfVertices];
int dist[numOfVertices];
if (BFS(adjList, source, dest, numOfVertices, pred, dist) == false)
{
cout << "Given source and destination are not connected";
return;
}
vector<int> path;
int crawl = dest;
path.push_back(crawl);
while (pred[crawl] != -1)
{
path.push_back(pred[crawl]);
crawl = pred[crawl];
}
cout << "Shortest path length is : " << dist[dest];
cout << "\nPath is::\n";
for (int i = path.size() - 1; i >= 0; i--)
cout << path[i] << " ";
}
bool BFS(vector<int> adjList[], int source, int dest, int numOfVertices, int pred[], int dist[])
{
list<int> queue;
bool visited[numOfVertices];
for (int i = 0; i < numOfVertices; i++)
{
visited[i] = false;
dist[i] = INT_MAX;
pred[i] = -1;
}
visited[source] = true;
dist[source] = 0;
queue.push_back(source);
while (!queue.empty())
{
int u = queue.front();
queue.pop_front();
for (int i = 0; i < adjList[u].size(); i++)
{
if (visited[adjList[u][i]] == false)
{
visited[adjList[u][i]] = true;
dist[adjList[u][i]] = dist[u] + 1;
pred[adjList[u][i]] = u;
queue.push_back(adjList[u][i]);
// We stop BFS when we find
// destination.
if (adjList[u][i] == dest)
return true;
}
}
}
return false;
}
"First, the user has to input two integers, lets say N and M. N holds the number of vertices and M holds the number of edges."
This is not a good idea. Humans are terrible at counting, while computers are pretty good at it. So do not make your users count the vertices and edges - they will often get it wrong and cause chaos.
Just input the start and ending nodes of an edge. If a node is already present in the data structure, connect it. If node not already present then add it and then connect it.
You will have much happier users!
I see that you have decided to store your graph in an adjacency list. This is a perfectly reasonable idea, but the snag is that it is quite a challenge to code. This seems to be your first attempt to code a graph theory problem, so I recommend that you use an adjacency matrix instead since it is much easier to code.
For small graphs the difference is insignificant, so you need only consider switching to the more complicate adjacency list when you are working with enormous graphs ( many thousands of nodes )
Remember that vectors in C++ are 0-based.
In your example, numOfVertices and numOfEdges are both 3, so node 3 will lead to out-of-bound access. Either change your input to 0-based node numbers or use node1-1 and node2-1.
See also
Vector going out of bounds without giving error
and the accepted answer.

graph rerouting algorithm hacker rank

I have tried to solve the problem Rerouting at hacker rank. I am posting here for help as competition is over.
https://www.hackerrank.com/contests/hack-the-interview-v-asia-pacific/challenges/rerouting
I have tried to solve problem using Strong connected components, but test cases failed. I can understand we have to remove cycles. But I stuck how to approach problem. Below is solution i have written. I am looking for guidence how to move forward so that i can apply my knowledge future based on mistakes i made here. Thanks for your time and help
int getMinConnectionChange(vector<int> connection) {
// Idea: Get number of strongly connected components.
int numberOfVertices = connection.size();
for(int idx = 0; idx < numberOfVertices; idx++) {
cout << idx+1 <<":"<< connection[idx] << endl;
}
stack<int> stkVertices;
map<int, bool> mpVertexVisited; //is vertex visited.think this as a chalk mark for nodes visited.
int numOFSCCs = 0;
int currTime = 1;
for (int vertexId = 0; vertexId < numberOfVertices; vertexId++) {
// check if node is already visited.
if (mpVertexVisited.find(vertexId+1) == mpVertexVisited.end()) {
numOFSCCs++;
mpVertexVisited.insert(make_pair(vertexId+1, true));
stkVertices.push(vertexId+1);
currTime++;
while (!stkVertices.empty()) {
int iCurrentVertex = stkVertices.top();
stkVertices.pop();
// get adjacent vertices. In this excercise we have only one neighbour. i.e., edge
int neighbourVertexId = connection[iCurrentVertex-1];
// if vertex is already visisted, don't insert in to stack.
if (mpVertexVisited.find(neighbourVertexId) != mpVertexVisited.end()) {
continue;
}
mpVertexVisited.insert(make_pair(neighbourVertexId, true));
stkVertices.push(neighbourVertexId);
} // while loop
} // if condition m_mapVrtxTimes.find(*itr) == m_mapVrtxTimes.end()
} // for loop of vertices
return numOFSCCs - 1;
}
This is a problem that I just solved and would like to share the solution.
The problem can be solved with union-find.
Two main observation:
The number of edges that has to be changed is the number of components - 1 (not necessarily strongly connected) Thus, union-find is handy here for finding the number of components
Second observation is that some component doesn't have terminating node, consider 1<->2, in other words, a cycle exist. We can detect whether there exists a terminating node if some node doesn't have an outgoing edge.
If all components have a cycle, it means that we need to change every component instead of a number of components - 1. This is to make it such that the graph will have a terminating point.
Code:
struct UF {
vector<int> p, rank, size;
int cnt;
UF(int N) {
p = rank = size = vector<int>(N, 1);
for (int i = 0; i < N; i++) p[i] = i;
cnt = N;
}
int find(int i) {
return p[i] == i ? i : p[i] = find(p[i]);
}
bool connected(int i, int j) {
return find(i) == find(j);
}
void join(int i, int j) {
if (connected(i, j)) return;
int x = find(i), y = find(j);
cnt--;
if (rank[x] > rank[y]) {
p[y] = x;
size[x] += size[y];
} else {
p[x] = y;
size[y] += size[x];
if (rank[x] == rank[y]) rank[y]++;
}
}
};
int getMinConnectionChange(vector<int> connection) {
int nonCycle = 0;
int n = connection.size();
UF uf(n);
for(int i=0;i<n;i++) {
int to = connection[i] - 1;
if(to == i) nonCycle++;
else uf.join(i, to);
}
int components = uf.cnt;
int countCycle = uf.cnt - nonCycle;
int res = components - 1;
if(countCycle == components) res++; // all components have cycle
return res;
}
TL;DR: you can view this as looking for a minimal spanning arborescence problem.
More precisely, add a node for each server, and another one called "Terminate".
Make a complete graph (each node is linked to every other one) and set as cost 0 for the edges corresponding to your input, 1 for the other ones.
You can use for example Edmond's algorithm to solve this.

String matching algorithm trying to correct it

I'm trying to do string matching algorithm a brute force method. but The algorithm is not working correctly, I get an out of bound index error.
here is my algorithm
int main() {
string s = "NOBODY_NOTICED_HIM";
string pattern="NOT";
int index = 0;
for (int i = 0; i < s.size();)
{
for (int j = 0; j < pattern.size();)
{
if(s[index] == pattern[j])
{
j++;
i++;
}
else
{
index = i;
j = 0;
}
}
}
cout<<index<<endl;
return 0;
}
FIXED VERSION
I fixed the out of bound exception. I don't know if the algorithm will work with different strings
int main() {
string s = "NOBODY_NOTICED_HIM";
string pattern="NOT";
int index = 0;
int i = 0;
while( i < s.size())
{
i++;
for (int j = 0; j < pattern.size();)
{
if(s[index] == pattern[j])
{
index++;
j++;
cout<<"i is " <<i << " j is "<<j <<endl;
}
else
{
index = i;
break;
}
}
}
cout<<i<<endl;
return 0;
}
Because the inner for loop has a condition to loop while j is less than pattern.size() but you are also incrementing i inside the body. When i goes out of bounds of s.size() then index also goes out of bounds and you'd get an OutOfBounds error.
The brute force method has to test the pattern with every possible subsequence. The main condition is the length, which has to be the same. All subsequence from s are:
['NOB', 'OBO', 'BOD', 'ODY', 'DY_', 'Y_N', 'NO', 'NOT', 'OTI', 'TIC',
'ICE', 'CED', 'ED', 'D_H', '_HI', 'HIM']
There are many ways to do it, you can do it char by char, or by using string operations like taking a substring. Both are nice excercises for learning.
Starting at zero in the s string you take the first three chars, compare to the pattern, and if equal you give the answer. Otherwise you move on to the char starting at one, etc.

C++ Connect 4 Checking Next Step Error

I am writing a Connect 4 game with minimax, but my next-step checking function is sometimes giving me unexpected results. Can you please tell me if my algorithm is correct?
For example if my board looks like this
0000000
0000000
0000000
0000000
1000000
2002120
it will return column 0 as true for player 2.
bool Board::check2(int player, int& bestMove)
{
for (int i=0; i<WIDTH; i++)
{
if(addToColumn(i, player))
{
if (checkNext(2, i, player))
{
bestMove=i;
removeFromColumn(i, player);
return true;
}
removeFromColumn(i, player);
}
}
return false;
}
bool Board::checkNextVertical(int size, int column, int player1)
{
int counter=0;
int player2;
if (player1==1)
{
player2=2;
}
else
player2=1;
for (int i=0 ; i<DEPTH; i++)
{
if (arrBoard[column][i]==player1)
{
counter++;
}
if (arrBoard[column][i]==player2)
{
return false;
}
if (counter==size)
{
return true;
}
}
return false;
}
bool Board::checkNextHorizontal(int size, int column, int player1)
{
int counter=0;
int player2;
if (player1==1)
{
player2=2;
}
else
player2=1;
for (int i=0 ; i<DEPTH; i++)
{
if (arrBoard[i][column]==player1)
{
for (int j = 0; j<WIDTH; j++)
{
if (arrBoard[i][j]==player1)
{
counter++;
}
if (arrBoard[i][j]!=player1)
{
counter=0;
}
if (counter==size)
{
return true;
}
}
}
}
return false;
}
bool Board::checkNext(int size, int column, int player)
{
if (checkNextVertical(size, column, player))
{
// printBoard();
return true;
}
if (checkNextHorizontal(size, column, player))
{
// printBoard();
return true;
}
return false;
}
Welcome to the forum.
There are a few problems with the code you posted:
Your checkNextVertical function appears to be attempting to check horizontally, and your checkNextHorizontal function appears to attempting to check both horizontally and vertically.
If you notice you use both arrBoard[column][i] and arrBoard[i][column]. I'm sure you'll agree only one of these can be correct. It's important to understand which is correct, or else your code will end up attempting to access locations in the array which are not valid, and you will get unexpected behaviour, for example your j loop in the checkNextHorizontal function is currently doing this.
It should be used as array[y / depth / row][x / width / column] - or whatever you will remember.
Personally, this code seems confusing:
int player2;
if (player1==1)
{
player2=2;
}
else
player2=1;
player2=1 seems like trying to push a square peg in a round hole. Could you use int player and set it to either 1 or 2 to make it easier to read?
I totally agree with Joachim - if you have these sorts of problems, it's always a great idea to fill the array with some data, then use the debugger to step through your code and check that the data being accessed is the data you expect to be accessed.
Alternatively, since it's a connect4 game, I assume at some point you know the column which the last move was made, in which case you can use this function to check if it was a winning move. You just need to tell it which column the last move was, and the required 'size' to win. If you do use it, I would still recommend stepping through it with the debugger so you can understand the array access. NB: your code wasn't checking diagonally - so neither does this. Some extra logic required if you want to do that:
bool winningMove(int column, int size)
{
bool winnerWinnerChickenDinner = false;
int player = 0;
int row = 0;
// Who was the last player to go in this column
// i.e. find the top non-zero entry
for (int i = 0; i < DEPTH; i++)
{
if (arrBoard[i][column] != 0)
{
player = arrBoard[i][column];
row = i;
break;
}
}
// If we found a player, check if it was a winning move
if (player != 0)
{
int count = 0;
// Loop twice, first horizontally, then vertically
for (int i = 0; i < 2 && !winnerWinnerChickenDinner; i++)
{
bool horizontal = (i == 0);
for (int j = 0; j < (horizontal ? WIDTH : DEPTH); j++)
{
// Check if we have 'size' consecutive entries by the same player
// (When we check horizontally, use arrBoard[row][j] to check the row)
// (When we check vertically, use arrBoard[j][column] to check the column)
if (arrBoard[(horizontal ? row : j)][(horizontal ? j : column)] == player)
{
if (++count == size)
{
winnerWinnerChickenDinner = true;
break;
}
}
else
{
count = 0;
}
}
}
}
return winnerWinnerChickenDinner;
}
The old games are the best - Connect4 is awesome, so good luck.

Positive rows in a matrix

I have to do an exercise for University that asks me to check ( for k times ) if a matrix has positive rows ( i mean a row with all positive elements ) , i think there's something wrong with the indices of for loops but i cannot find the mistakes.
i tried to debug with a cout statement apply to the counter an it gives me "101" , so it seems like compiler assign "1" to the positive rows and "0" to the negative
This is the code i wrote:
#include <iostream>
using namespace std;
const int N = 3;
bool positive(int a[N][N], int row[N], int x) {
bool condition = false;
for(int i = 0; i < N; i++) {
row[i] = a[x][i];
}
int j = 0;
while(j < N) {
if(row[j] >= 0) {
condition = true;
} else {
condition = false;
}
j++;
}
return condition;
}
bool function (int a[N][N], int z, int j, int k) {
int b[N];
int c[N];
int count = 0;
if(positive(a, b, z) && positive(a, c, j)) {
count++;
}
if(count == k) {
return true;
} else {
return false;
}
}
int main() {
int a[N][N] = {
{
2, 8, 6
}, {
-1, - 3, - 5
}, {
6, 10, 9
}
};
int k = 2;
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
if(function (a, i, j, k)) {
cout << "OK";
} else {
cout << "NO";
}
}
}
return 0;
}
You should probably take another look at this problem and restart with a different solution. The objective is pretty easy but your code is surprisingly complex and some of it doesn't really make sense.
For example, if you had a matrix like this:
1 2 4 --> matrix A
-1 8 -6
3 9 2
You have N=3 rows and columns. The only thing you have to to based on what you said is take the matrix, cycle through the N rows, and for each row, check it's N columns to see if anything is < 0.
Doing this K times, as you put it, makes no sense. The matrix will be the same every time you compare it since you're not changing it, why would you do it more than once? I think you should reread the assignment brief there.
As for the logic of finding which rows are positive or negative, just do something simple like this.
//Create array so we have one marker for each row to hold results.
bool rowPositiveFlags[N] = { true, true, true };
//Cycle through each row.
for (int row = 0; row < N; ++row)
//Cycle through every column in the current row.
for (int col = 0; col < N; ++col)
//If the column is negative, set the result for this row to false and break
//the column for loop as we don't need to check any more columns for this row.
if (A[row][col] < 0) {
rowPositiveFlags[row] = false;
break;
}
You should always name things so that you can read your code like a book. Your i's, j's, and k's just make something simple confusing. As for the problem, just plan out your solution.
Solve the problem by hand on paper, write the steps in comments in your code, and then write code below the comments so what you do definitely makes sense and isn't overkill.
And this is a great site, but next time, post a smaller piece of code that shows your problem. People shouldn't ever give you a full solution here for homework so don't look for one. Just find the spot where your indices are broken and paste that set of 5 lines or whatever else is wrong. People appreciate that and you'll get faster, better answers for showing the effort :)