The problem is a part of my computer science homework. The homework includes 5 different types of students that travel through a given weighted undirected node graph where each student has a different method. The fifth student is the most difficult one and I haven't been able to implement it efficiently.
The fifth student has a secret power, (s)he can teleport between adjacent nodes, so it takes 0 time to travel between them. However, to recharge that secret power, (s)he needs to pass two edges, and (s)he does not have that secret power at the beginning of his/her journey. Unlike other four students, (s)he can use the same edge multiple times, so in the first move, (s)he may go N_1->N_2 and N_2->N_1 to recharge his/her secret power. (S)he cannot store his/her secret power and must use it right away after after gaining it.
The fifth student wants to know the shortest time to reach the summit. At start, (s)he does not have any power, so (s)he needs to pass two edges to recharge it.
The method i tried was a modification of Dijkstra's Algorithm; where instead of moving node by node, from one node it calculates all three possible jumps, only considering the weights of the first two jumps. It considers all cases such as going to a node and coming back to recharge power and jump a highly weighted node. It does work and i do get all the correct answers for the given test cases, but it is SLOW. We are under a two second limit and right now my algorithm takes around 4 seconds for test cases with 50 000 nodes and 100 000 edges.
I'm guessing the problem is within reaching neighbors since there are 3 nested for loops to reach all possible 3 jump away neighbors (while also being able to use the same edges more than once), which basically makes this O(n^3) (But I'm not great with big-oh notation so I'm not sure if it's actually that.)
Does anyone have any ideas to make this algorithm more efficient, or a different algorithm that isn't so slow?
Any help is appreciated!
Here's the code if it's of any help.
long long int HelpStudents::fifthStudent() {
auto start = std::chrono::system_clock::now();
set< pair<long long int,int> >setds;
vector<long long int> dist(totalNodes+15,std::numeric_limits<long long int>::max());
setds.insert(make_pair(0,1));
dist[1] = 0;
bool change = false;
int counter = 0; //these variables were just for checking some things
int max_counter = 0;
int changed_summit = 0;
int operations_after_last_change = 0;
int w1;
int w2;
int db = 0;
vector<int> neighbors;
vector<int> neighbors2;
vector<int> neighbors3;
int u;
while(!setds.empty()){
pair<long long int,int> tmp = *(setds.begin());
setds.erase(setds.begin());
u = tmp.second; //vertex label
if(dist[u] > dist[summit_no]){
continue;
}
if(!change){
counter++;
}else{
counter = 0; //debugging stuff
}
db++;
//cout << db2 << endl;
operations_after_last_change++;
max_counter = max(counter,max_counter);
//cout << "counter: " << counter <<endl;
change = false;
neighbors = adjacency_map[u]; //adjacency map holds a vector which contains the adjacent nodes for the given key
//cout << "processing: " << "(" << tmp.first << ","<< tmp.second << ") " << endl;
for(int nb : neighbors){
w1 = getWeight(u,nb); //this is one jump,
//nb is neighboor
neighbors2 = adjacency_map[nb];
//cout << "\t->" << nb << endl;
if( nb == summit_no){
if(dist[nb] > dist[u] + (w1)){
auto t = setds.find(make_pair(dist[nb],nb));
if(t != setds.end()){
setds.erase(t);
}
dist[nb] = dist[u] + (w1);
change = true;
changed_summit++;
operations_after_last_change = 0;
//cout << "changed summit to " << (dist[u] + (w1)) << endl;
//continue;
}
}
for(int nb2: neighbors2){ //second jump
w2 = getWeight(nb,nb2);
//cout << "\t\t->" << nb2 << endl;
if( nb2 == summit_no){
if(dist[nb2] > dist[u] + (w1+w2)){
auto t = setds.find(make_pair(dist[nb2],nb2));
if(t != setds.end()){
setds.erase(t);
}
dist[nb2] = dist[u] + (w1+w2);
change=true;
changed_summit++;
operations_after_last_change = 0;
//cout << "changed summit to " << (dist[u] + (w1+w2)) << endl;
//continue;
}
}
neighbors3 = adjacency_map[nb2];
for(int nbf: neighbors3){ //third jump, no weight
//cout << "\t\t\t->" << nbf;
if(dist[nbf] > dist[u] + (w1+w2)){
auto t = setds.find(make_pair(dist[nbf],nbf));
if(t != setds.end()) {
setds.erase(t);
}
change = true;
dist[nbf] = dist[u] + (w1+w2);
if(nbf == summit_no){
changed_summit++;
operations_after_last_change = 0;
//cout << endl;
}else{
setds.insert(make_pair(dist[nbf],nbf));
//cout << "\t\t\t\t inserted ("<<dist[nbf]<<","<<nbf<<")" << endl;
}
//cout << "changed " << nbf << " to " << (dist[u] + (w1+w2)) << "; path: "<< u <<" -> "<<nb<<" -> "<<nb2 << " -> " <<nbf << endl;
//setds.insert(make_pair(dist[nbf],nbf));
}else{
//cout << endl;
}
}
}
}
}
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
cout << "time passed: "<< elapsed_seconds.count() <<" total loop: "<<db<< endl;
return dist[summit_no];
Aucun commentaire:
Enregistrer un commentaire