How to find shortest path between every node within K moves? - c++

Lets say I have following graph:
Now what I want is to get shortest path between every node in graph(or have -1 at that place in matrix if it is not possible to get from 1 node to other) , but that path need to have lenght less or same as K.
Now I tried using floyd-warshall algorithm replacing automatically path from 1 node to other if its length is less then K ,but that algorithm did not work on any test cases(not Time limit exceeded but Wrong answer).
This is how I did it:
// N is number of nodes, l is matrix, in l[x][y][0] I have shortest path from x to y and in l[x][y][1] is its lenght
for (int k = 0; k < N; k++) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
//if (this new path is shorter or there is not path yet) and current path lenght is not K(if it already reached max size) and both paths are not -1.
if((l[i][j][0]>l[i][k][0]+l[k][j][0] || l[i][j][0]==-1) && l[i][j][1]<K && l[i][k][0]>-1 && l[k][j][0]>-1){
//change max size
l[i][j][0]=l[i][k][0]+l[k][j][0];
//lenght of that path +=1
l[i][j][1]+=1;
}
}
}
}
for same number(like 3 and 3) I know it is wrong but later when outputing I puted that just print 0.

l[i][j][1]+=1; it's wrong it should actually be l[i][j][1]=l[i][k][1]+l[k][j][1]; but this brakes your solution logic. So i recommend you do like this: count log(K) matrices: i-th matrix means length from j to k in no more than 2^i moves. Look at K in binary and when it-s 1 on i-th place you should recalc your ~current~ matrix with i-th matrix like this (not tested just for show the idea but seems that it would works. maybe should do --K for strict inequality):
#include <iostream>
#include <vector>
int my_log2(int index){
int targetlevel = 0;
while (index >>= 1) ++targetlevel;
return targetlevel;
}
int main(){
int N;
int K;
std::cin >> N >> K;
std::vector < std::vector < std::vector < int > > > dist(my_log2(K), std::vector < std::vector < int > > (N, std::vector < int > (N)));
for (int i = 0; i < N; ++i){
for (int j = 0; j < N; ++j){
// assume weights are positive and -1 if no edge between vertices
// assume that dist[0][i][i] == 0
std::cin >> dist[0][i][j];
}
}
// can be easy rewriten to negative weights with same idea
for (int i = 1; i < my_log2(K); ++i){
for (int j = 0; j < N; ++j){
for (int k = 0; k < N; ++k){
dist[i][j][k] = -1;
for (int l = 0; l < N; ++l){
if (dist[i - 1][j][l] > -1 && dist[i - 1][l][k] > -1 && (dist[i][j][k] == -1 || dist[i][j][k] > dist[i - 1][j][l] + dist[i - 1][l][k])){
dist[i][j][k] = dist[i - 1][j][l] + dist[i - 1][l][k];
}
}
}
}
}
std::vector < std::vector < int > > old_current(N, std::vector < int > (N, -1));
for (int i = 0; i < N; ++i){
old_current[i][i] = 0;
}
for (int i = 0; i < my_log2(K); ++i){
std::vector < std::vector < int > > new_current(N, std::vector < int > (N, -1));
if (((K >> i) & 1) == 1){
for (int j = 0; j < N; ++j){
for (int k = 0; k < N; ++k){
for (int l = 0; l < N; ++l){
if (old_current[j][l] > -1 && dist[i][l][k] > -1 && (new_current[j][k] == -1 || new_current[j][k] > old_current[j][l] + dist[i][l][k])){
new_current[j][k] = old_current[j][l] + dist[i][l][k];
}
if (dist[i][j][l] > -1 && old_current[l][k] > -1 && (new_current[j][k] == -1 || new_current[j][k] > dist[i][j][l] + old_current[l][k])){
new_current[j][k] = dist[i][j][l] + old_current[l][k];
}
}
}
}
}
old_current = new_current;
}
// asnwer is in old_current
}

Related

Find a sum of all positive matrix elements that located before of the largest positive element

here is what i tried before:
//finding maximum
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (arr[i][j] > max)
{
max = arr[i][j];
imax = i;
jmax = j;
}
}
}
//finding a sum
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (arr[i][j] > 0)
{
if (i <= imax && j < jmax)
sum += arr[i][j];
}
}
}
cout << "sum = " << sum << endl;
}
but that algorithm doesn't count it right, how should i do to make it work?
looks like that my code is "limitng" the range of search, because of wrong condition and i duuno how to make it right?
Let's think step by step.
Assuming, imax is the row number and jmax is the column number of the maximum elements present in the matrix.
Row selection procedure:
So, to accomplish our object, we will traverse row which is <= imax. That means, we'll consider the value of the current row as our answer only if current row <= imax. If the current row becomes larger than row, then we can stop traversing .
//finding a sum
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (arr[i][j] > 0)
{
if(i <= imax)
{
// do something
}
else
{
break;
}
}
}
}
We can also do it in below way:
//finding a sum
for (int i = 0; i < n && i <= imax; ++i)
{
for (int j = 0; j < n; ++j)
{
if (arr[i][j] > 0)
{
}
}
}
Column selection procedure:
It's a little bit different from the row selection procedure.
We can consider every column unless current row is equal to imax. That means when
current row < imax we will consider values of every column, but when current row == imax we'll only consider smaller column's value as our answer.
//finding a sum
for (int i = 0; i < n && i <= imax; ++i)
{
for (int j = 0; j < n; ++j)
{
if(i < imax && arr[i][j] > 0)
{
// consider the value for answer
}
else
{
// here i == imax
// so we'll only consider smaller column's value as our answer
if(j < jmax && arr[i][j] > 0)
{
// consider the value for answer
}
else if(j >= jmax) // we've come out of the boundary. No matter the value is positive or negative, we don't need to check any further
{
break;
}
}
}
}
Overall code of finding sum portion will look like this:
//finding a sum
for (int i = 0; i < n && i <= imax; ++i)
{
for (int j = 0; j < n; ++j)
{
if(i < imax && arr[i][j] > 0)
{
// consider the value for answer
sum += arr[i][j];
}
else
{
// here i == imax
// so we'll only consider smaller column's value as our answer
if(j < jmax && arr[i][j] > 0)
{
// consider the value for answer
sum += arr[i][j];
}
else if(j >= jmax) // we've come out of the boundary. No matter the value is positive or negative, we don't need to check any further
{
break;
}
}
}
}
Note: Don't forget to initialize the value of max , imax, jmax and sum properly.
So this doesn't work the way you've set it up.
Suppose you have a matrix like this:
0 1 5 10 8
4 22 8 18 11
1 2 6 14 9
1 27 6 14 9
1 2 6 14 9
Your max would find that imax = 3, jmax = 1
What happens when you try to count the element at [0, 5]? You miss it because jmax = 1, means all elements to the right of the j =1 column aren't counter by your conditions.
It is not clear what you mean with "located before", but I am almost certain that this is the issue in your code. Supposed the max element is x then you add all elements marked with o and exclude elements marked with .:
ooo...
ooo...
oox...
......
......
But I'd rather expect either this
oooooo
oooooo
oox...
......
......
or this:
ooo...
ooo...
oox...
oo....
oo....

Skipping vector iterations based on index equality

Let's say I have three vectors.
#include <vector>
vector<long> Alpha;
vector<long> Beta;
vector<long> Gamma;
And let's assume I've filled them up with numbers, and that we know they're all the same length. (and we know that length ahead of time - let's say it's 3.)
What I want to have at the end is the minimum of all sums Alpha[i] + Beta[j] + Gamma[k] such that i, j, and k are all unequal to each other.
The naive approach would look something like this:
#include <climits>
long min = LONG_MAX;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k=0; k < 3; k++) {
if (i != j && i != k && j != k) {
long sum = Alpha[i] + Beta[j] + Gamma[k];
if (sum < min)
min = sum;
}
}
}
}
Frankly, that code doesn't feel right. Is there a faster and/or more elegant way - one that skips the redundant iterations?
The computational complexity of your algorithm is an O(N^3). You can save a very small bit by using:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if ( i == j )
continue;
long sum1 = Alpha[i] + Beta[j];
for (int k=0; k < 3; k++) {
if (i != k && j != k) {
long sum2 = sum1 + Gamma[k];
if (sum2 < min)
min = sum2;
}
}
}
}
However, the complexity of the algorithm is still O(N^3).
Without the if ( i == j ) check, the innermost loop will be executed N^2 times. With that check, you will be able to avoid the innermost loop N times. It will be executed N(N-1) times. The check is almost not worth it .
If you can temporarily modify the input vectors, you can swap the used values with the end of the vectors, and just iterate over the start of the vectors:
for (int i = 0; i < size; i++) {
std::swap(Beta[i],Beta[size-1]); // swap the used index with the last index
std::swap(Gamma[i],Gamma[size-1]);
for (int j = 0; j < size-1; j++) { // don't try the last index
std::swap(Gamma[j],Gamma[size-2]); // swap j with the 2nd-to-last index
for (int k=0; k < size-2; k++) { // don't try the 2 last indices
long sum = Alpha[i] + Beta[j] + Gamma[k];
if (sum < min) {
min = sum;
}
}
std::swap(Gamma[j],Gamma[size-2]); // restore values
}
std::swap(Beta[i],Beta[size-1]); // restore values
std::swap(Gamma[i],Gamma[size-1]);
}

why this algorithm (Floyd Warshal algorithm) only works for 100000007?

This is Floyd Warshal algorithm which i'm using to find the maximum of minimum path in a graph. Why this algorithm don't work if i put INT_MAX or any other big integer like 2147483647 in place of 100000007.
int main() {
int c,f; //c=number of vertice
// f=number of pair of vertices directly connected
cin >> c >> f;
int graph[c][c];
for(int i = 0;i < c;i++)
for(int j = 0;j < c;j++)
graph[i][j] = 100000007;
for(int i = 0;i < c;i++)
graph[i][i] = 0;
int x,y,p;
for(int i = 0;i < f;i++) {
cin >> x >> y >> p;
graph[x-1][y-1] = p;
graph[y-1][x-1] = p;
}
int dist[c][c], i, j, k;
for(i = 0; i < c; i++)
for (j = 0; j < c; j++)
dist[i][j] = graph[i][j];
for(k = 0; k < c; k++) {
for(i = 0; i < c; i++) {
for(j = 0; j < c; j++) {
if(dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
int ans = 0;
for(int i = 0;i < c;i++)
for(int j = 0;j < c;j++)
ans = max(ans,dist[i][j]);
cout << ans << endl;
return 0;
}
(as in the comments)
Once your value for infinity is greater than INT_MAX / 2, which is 1,073,741,823, the line if(dist[i][k] + dist[k][j] < dist[i][j]) has an overflow in it. Overflow is undefined behavior in C++, but the most likely outcome is that dist[i][k] + dist[k][j] becomes a negative value, and in the next line, dist[i][j] = dist[i][k] + dist[k][j];, actual distances get overwritten by such negative values.
The value you need for infinity should be greater than any real distance you can encounter. If that distance exceeds 230 - 1, consider using a type with higher upper limit (unsigned int32, int64, or even a double).

Trying to multiply two dynamically created matrices(2d vector's) together in c++

So what I am trying to do is multiply one 2d vector by another 2d vector.
I come from Java,Python and C# so I am pretty much learning C++ as I go along.
I have the code down to generate the vector and display the vector but I can't seem to finish the multiplication part.
v1 is another matrix that is already generated.
vector<vector<int> > v2 = getVector();
int n1 = v1[0].size();
int n2 = v2.size();
vector<int> a1(n2, 0);
vector<vector<int> > ans(n1, a1);
for (int i = 0; i < n1; i++) {
for (int j = 0; j < n2; j++) {
for (int k = 0; k < 10; k++) {
// same as z[i][j] = z[i][j] + x[i][k] * y[k][j];
ans[i][j] += v1[i][k] * v2[k][j];
}
}
}
displayVector(ans);
My guess for where I am going wrong is in the inner-most loop. I can't figure out what to actually put in place of that 10 I have there now.
When you multiply matrices, the number of columns of the matrix on the left side must equal the number of rows of the matrix on the right side. You need to check that that is true, and use that common number for your size of the k variable:
int nCommon = v1.size();
assert(v2[0].size() == nCommon);
for (int i = 0; i < n1; i++) {
for (int j = 0; j < n2; j++) {
for (int k = 0; k < nCommon ; k++) {
ans[i][j] += v1[i][k] * v2[k][j];
}
}
}
For you inner loop, you should do something like this
ans[i][j] = 0;
for (int k = 0; k < n2; k++) {
ans[i][j] += v1[i][k] * v2[k][j];
}
I don't know where the 10 comes from.

Dynamic approach to the TSP

I'm having trouble recognizing why this algorithm doesn't return the shortest path for the TSP.
vector<int> tsp(int n, vector< vector<float> >& cost)
{
long nsub = 1 << n;
vector< vector<float> > opt(nsub, vector<float>(n));
for (long s = 1; s < nsub; s += 2)
for (int i = 1; i < n; ++i) {
vector<int> subset;
for (int u = 0; u < n; ++u)
if (s & (1 << u))
subset.push_back(u);
if (subset.size() == 2)
opt[s][i] = cost[0][i];
else if (subset.size() > 2) {
float min_subpath = FLT_MAX;
long t = s & ~(1 << i);
for (vector<int>::iterator j = subset.begin(); j != subset.end(); ++j)
if (*j != i && opt[t][*j] + cost[*j][i] < min_subpath)
min_subpath = opt[t][*j] + cost[*j][i];
opt[s][i] = min_subpath;
}
}
vector<int> tour;
tour.push_back(0);
bool selected[n];
fill(selected, selected + n, false);
selected[0] = true;
long s = nsub - 1;
for (int i = 0; i < n - 1; ++i) {
int j = tour.back();
float min_subpath = FLT_MAX;
int best_k;
for (int k = 0; k < n; ++k)
if (!selected[k] && opt[s][k] + cost[k][j] < min_subpath) {
min_subpath = opt[s][k] + cost[k][j];
best_k = k;
}
tour.push_back(best_k);
selected[best_k] = true;
s -= 1 << best_k;
}
tour.push_back(0);
return tour;
}
For example, on a distance cost matrix of just 5 points (5 different nodes in the graph), the algorithm returns a path that's less than optimal. Any help in recognizing a blatant or small error would be appreciated. Or any helpful tips as to what's going wrong.
One thing that looks odd is that the main for loop does things even if i is not part of the subset s.
In other words, opt[17][8] will be set to cost[0][8]. opt[17][8] represents the state of being at node 8, and having visited nodes 0 and 4 (because 5=2^0+2^4).
This should be marked as being impossible because if we are at node 8, we must certainly have visited node 8!
I would suggest preventing these cases from occuring by changing:
for (int i = 1; i < n; ++i) {
vector<int> subset;
to
for (int i = 1; i < n; ++i) {
vector<int> subset;
if ((s&(1<<i))==0) {
opt[s][i]=FLT_MAX;
continue;
}
Nested loop for(j= iterates over all nodes in subset, including the starting node. This results in using uninitialized values opt[t][0] and therefore in incorrect optimal path length calculation.
The easiest fix would be to exclude starting node from subset:
for (int u = 1; u < n; ++u)
...
if (subset.size() == 1)
...
else if (subset.size() > 1)