How to improve Dijkstra algorithm when querying n times? - algorithm
I'm currently working on a problem at Codechef. You can find the problem statement here:
Delivery Boy
In short, the problem is asking to query n times the shortest path from a start to an end. My solution is to use Dijsktra with priority_queue plus caching the result into a hash_map in case we already had a start. Unfortunately, I got time limit exceed many times and I couldn't find a better way to make it faster. I wonder am I in the right track? or there is a better algorithm to this problem?
By the way, since the contest is still going, please don't post any solution. A hint is more than enough to me. Thanks.
Here is my attempt:
#ifdef __GNUC__
#include <ext/hash_map>
#else
#include <hash_map>
#endif
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <utility>
#include <stack>
#include <deque>
#include <queue>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
using namespace std;
#ifdef __GNUC__
namespace std {
using namespace __gnu_cxx;
}
#endif
const int MAX_VERTICES = 250;
const int INFINIY = (1 << 28);
int weight[MAX_VERTICES + 1][MAX_VERTICES + 1];
bool visited_start[MAX_VERTICES + 1] = { 0 };
struct vertex {
int node;
int cost;
vertex(int node = 0, int cost = 0)
: node(node), cost(cost) {
}
bool operator <(const vertex& rhs) const {
return cost < rhs.cost;
}
bool operator >(const vertex& rhs) const {
return cost > rhs.cost;
}
};
hash_map<int, vector<vertex> > cache;
typedef priority_queue<vertex, vector<vertex>, greater<vertex> > min_pq;
vector<vertex> dijkstra_compute_path(int start, int n) {
min_pq pq;
vector<vertex> path;
vector<int> visited(n, 0);
int min_cost = 0;
int better_cost;
vertex u;
for (int i = 0; i < n; ++i) {
path.push_back(vertex(i, INFINIY));
}
path[start].cost = 0;
pq.push(vertex(start, path[start].cost));
while (!pq.empty()) {
// extract min cost
u = pq.top();
pq.pop();
// mark it as visited
visited[u.node] = 1;
// for each vertex v that is adjacent to u
for (int v = 0; v < n; ++v) {
// if it's not visited, visit it
if (visited[v] == 0) {
better_cost = path[u.node].cost + weight[u.node][v];
// update cost
if (path[v].cost > better_cost) {
path[v].cost = better_cost;
pq.push(vertex(v, path[v].cost));
}
}
}
}
return path;
}
void check_in_cache(vector<vertex>& path, int start, int no_street) {
if (visited_start[start] == 0) {
path = dijkstra_compute_path(start, no_street);
cache.insert(make_pair(start, path));
visited_start[start] = 1;
}
else {
path = cache[start];
}
}
void display_cost(int stop_at_gas_cost, int direct_cost) {
printf("%d ", stop_at_gas_cost);
if (stop_at_gas_cost > direct_cost) {
printf("%d\n", stop_at_gas_cost - direct_cost);
}
else {
printf("0\n");
}
}
void handle_case_one() {
int no_scenario;
int dummy;
int s, g, d;
scanf("%d", &dummy);
scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &s, &g, &d);
printf("0 0\n");
}
}
void inout_delivery_boy() {
int no_street;
int no_scenario;
int restaurant;
int gas_station;
int destination;
int stop_at_gas_cost;
int direct_cost;
vector<vertex> direct;
vector<vertex> indirect;
vector<vertex> d;
int c;
scanf("%d", &no_street);
if (no_street == 1) {
handle_case_one();
return;
}
for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
scanf("%d", &c);
weight[x][y] = c;
}
}
for (int i = 0; i < no_street; ++i) {
d.push_back(vertex(i, INFINIY));
}
scanf("%d", &no_scenario);
for (int i = 0; i < no_scenario; ++i) {
scanf("%d %d %d", &restaurant, &gas_station, &destination);
// check in cache
check_in_cache(direct, restaurant, no_street);
check_in_cache(indirect, gas_station, no_street);
// calculate the cost
stop_at_gas_cost = direct[gas_station].cost + indirect[destination].cost;
direct_cost = direct[destination].cost;
// output
display_cost(stop_at_gas_cost, direct_cost);
}
}
void dijkstra_test(istream& in) {
int start;
int no_street;
int temp[4] = { 0 };
vector<vertex> path;
in >> no_street;
for (int x = 0; x < no_street; ++x) {
for (int y = 0; y < no_street; ++y) {
in >> weight[x][y];
}
}
// arrange
start = 0;
temp[0] = 0;
temp[1] = 2;
temp[2] = 1;
temp[3] = 3;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 1;
temp[0] = 1;
temp[1] = 0;
temp[2] = 2;
temp[3] = 4;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 2;
temp[0] = 2;
temp[1] = 1;
temp[2] = 0;
temp[3] = 3;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
// arrange
start = 3;
temp[0] = 1;
temp[1] = 1;
temp[2] = 1;
temp[3] = 0;
// act
path = dijkstra_compute_path(start, no_street);
// assert
for (int i = 0; i < no_street; ++i) {
assert(path[i].cost == temp[i]);
}
}
int main() {
// ifstream inf("test_data.txt");
// dijkstra_test(inf);
inout_delivery_boy();
return 0;
}
please notice N is small in the problem. have you tried Floyd shortest path algorithm to pre-calculate shortest path between each two nodes ? it will cost O(N^3) time, which is 250^3=15625000 in the problem, should be easy to be finished running in 1 second. Then you can answer each query in O(1).
the introduction of Floyd :
http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
ps: i think cached dijstra costs a maximum running time of O(N^3) for overall test case as well . but the way you implement the cache will spend more unnecessary time on memory copying, which may lead to a TLE. Just a guess.
Indeed Floyd-Warshall's Algorithm is better than Dijkstra's in this case, the complexity for Dijkstra is O(m*n^2) and in this problem M is much much higher than N so the O(n^3) time complexity of Floyd-Warshall is better.
Related
How to use unique pointers to create matrix?
I have to create a matrix using unique poiters that permit operations: Matrix a,b; Matrix c(b) and Matrix d=a; So far I did the simple implementing of a matrix class Matrix { public:vector<vector<int>> data; Matrix() {} Matrix(vector<vector<int>> matrix) { this->data=matrix; } Matrix (const Matrix& m2) { this->data=m2.data; } Matrix& operator= (const Matrix &m2) { this->data = m2.data; return *this; } } It's first time for me facing unique_ptr vectors, I found a plenty of informations about unique_ptr vectors creating arrays, but not much for matrix, it's so unclear. How can I use unique_ptr vectors(I must use them) instread of simple vector? Any help is welcome, thank you!
Try this for init matrix only with std::unique_ptr [1]: const int rowCount = 3; const int clmnCount = 6; std::unique_ptr<std::unique_ptr<int[]>[]> matrix(new std::unique_ptr<int[]>[rowCount]()); // or // auto matrix = new std::unique_ptr<int[]>[rowCount](); for (int i = 0; i < rowCount; i++) matrix[i] = std::make_unique<int[]>(clmnCount); Example of use [1]: #include <iostream> #include <iomanip> #include <memory> int main() { const int rowCount = 3; const int clmnCount = 6; std::unique_ptr<std::unique_ptr<int[]>[]> matrix(new std::unique_ptr<int[]>[rowCount]()); for (int i = 0; i < rowCount; i++) { matrix[i] = std::make_unique<int[]>(clmnCount); for (int j = 0; j < clmnCount; j++) { matrix[i][j] = j; std::cout << std::setw(3) << matrix[i][j]; } std::cout << std::endl; } } Or if u want use std::vector of std::unique_ptr try this [2]: const int rowCount = 3; const int clmnCount = 6; std::vector<std::unique_ptr<int[]>> matrix; for (int i = 0; i < rowCount; i++) matrix.push_back(std::make_unique<int[]>(clmnCount)); Example of use [2]: #include <iostream> #include <iomanip> #include <memory> #include <vector> int main() { const int rowCount = 3; const int clmnCount = 6; std::vector<std::unique_ptr<int[]>> matrix; for (int i = 0; i < rowCount; i++) { matrix.push_back(std::make_unique<int[]>(clmnCount)); for (int j = 0; j < clmnCount; j++) { matrix[i][j] = j; std::cout << std::setw(3) << matrix[i][j]; } std::cout << std::endl; } }
Schedule round robin matches
How to implement a round robin schedule for an array of 4 elements [1,2,3,4]? The result of the algorithm should be able to display, for each element, the list of the players it will face in chronological order: (1: 4,2,3) (2: 3,1,4) (3: 2,4,1) (4: 1,3,2) Line 1: 4,2,3 means that the player (1) will face in order the players (4), (2) and (3). Of the same way, line 2: 3,1,4 indicates that the player (2) will face in order the players (3), (1) and (2). We have implemented this code but we encounter a bug when we start filling in the name of the player. Do you have any idea about this problem? #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME_MAX_LENGTH 20 #define NUM_MIN_PLAYERS 2 #define NUM_MAX_PLAYERS 20 enum Style { STYLE_COMPACT, STYLE_TABLE }; enum Format { FORMAT_ID, FORMAT_NAME }; struct PlayerList { unsigned int num_players; char name[NUM_MAX_PLAYERS][NAME_MAX_LENGTH + 1]; }; struct Grid { unsigned int num_players; unsigned int day[NUM_MAX_PLAYERS] [NUM_MAX_PLAYERS]; }; void printList(struct PlayerList *list) { for (int i = 0; i < list->num_players; i++) { printf("%d:%s\n", i + 1, list->name[i]); } } struct Grid calculer_berger(struct PlayerList *list) { struct Grid grid; // algo pour remplir la grid grid.num_players = list->num_players; int i, j; for (i = 0; i < list->num_players - 1; i++) { for (j = 0; j < list->num_players - 1; j++) { if (i == j) { /* edge cases */ grid.day[i][list->num_players - 1] = ((i + j) + (i + j) / list->num_players) % list->num_players; grid.day[list->num_players - 1][j] = ((i + j) + (i + j) / list->num_players) % list->num_players; grid.day[i][j] = 0; } else { grid.day[i][j] = ((i + j) + (i + j) / list->num_players) % list->num_players; } } } grid.day[0][list->num_players - 1] = list->num_players - 1; grid.day[list->num_players - 1][list->num_players - 1] = 0; grid.day[list->num_players - 1][0] = list->num_players - 1; return grid; } void permuter(struct Grid *grid) { int tmp; for (int i = 0; i < grid->num_players; i++) { for (int j = 1; j <= grid->num_players / 2; j++) { tmp = grid->day[i][j]; grid->day[i][j] = grid->day[i][grid->num_players - j]; grid->day[i][grid->num_players - j] = tmp; } } } void print_grid(struct Grid *grid, struct PlayerList *list) { for (int i = 0; i < grid->num_players; i++) { for (int j = 0; j < grid->num_players; j++) { if (j == 0) { printf("%d:", grid->day[i][j] + 1); } else { printf("%d", grid->day[i][j] + 1); if (j < grid->num_players - 1) { printf(","); } } } printf("\n"); } } int main(int argc, char **argv) { struct PlayerList playerList; char nom[NAME_MAX_LENGTH + 1]; int nbCharLu = 0; while ((nbCharLu = fscanf(stdin, "%s", nom)) != -1) { strcpy(playerList.name[playerList.num_players], nom); playerList.num_players++; } struct Grid myGrid = calculer_berger(&playerList); printList(&playerList); print_grid(&myGrid, &playerList); printf("Apres la permut\n"); permuter(&myGrid); print_grid(&myGrid, &playerList); return 0; }
Assuming you are storing the elements in an Integer array and that you would like to just display the results. Here is one implementation....The code should accommodate "N" values because of the use of "sizeof".... feel free to customize it further.... #include <stdio.h> int main() { int i,j; int array[] = {1,2,3,4}; for(i = 0; i < sizeof(array)/sizeof(int);++i){ printf("(%d :",array[i]); for(j = 0; j < sizeof(array)/sizeof(int);++j){ if(j == i) continue; printf("%d ",array[j]); } printf(")\n"); } }
#include <stdio.h> void main() { int mid; int num; int j, temp; int k = 0; int num1; int data[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14}; num = sizeof(data)/sizeof(int); mid = (sizeof(data)/sizeof(int))/2; while(k < num - 1){ printf("Round %d ( ",k+1); num1 = num; for(int i = 0;i < mid;i++,num1--) /*pairing the competitors in each round*/ printf("%d:%d ",data[i],data[num1-1]); for(int i = 0,j = num-1; i < num -2;i++,j--){ /* fixing the first competitor and rotating the others clockwise*/ temp = data[j]; data[j] = data[j-1]; data[j-1] = temp; } printf(")\n"); k++; } }
how to fastly find array which include some numbers(1~255)?
I want to solve some algorithm problem. Could you suggest any algorithms working more fast? *Problem summary - Find same array of key[200] is same as source array KEY[200] - Each element of KEY[200] array is random numbers range 1~255 - only 2 file are given. - You must implement just function find_array() of user_code.cpp - It is not allowed to edit any other things - You can use check() function for finding array - test case is 50, time limit is 10 sec for 50 test case, memory limit is 256MB. #include <stdio.h> #include <stdlib.h> #include <time.h> extern void find_array(unsigned char key[200]); unsigned char KEY[200]; int check(unsigned char key[200]) { int pos = 0; int equal = 0; for (int c = 0; c < 200; c++) { if (key[c] == KEY[c]) pos++; } for (int c1 = 0; c1 < 200; c1++) { for (int c2 = 0; c2 < 200; c2++) { if(key[c1] == KEY[c2]) equal++; } } return pos * 256 + equal; } int main() { for (int t = 0; t < 1; t++) //test case 50개 { for (int i = 0; i < 200; i++) { KEY[i] = rand() % 255 + 1; //1~255 } unsigned char key[200] = { 0, }; find_array(key); //you must implement this function } return 0; } //user_code.cpp extern int check(unsigned char key[200]); //you must implement this function //below is my code take a long time(about 2sec for each case) void find_array(unsigned char key[200]) { unsigned char temp[200]; int result, pos, equal; for (int k = 0; k < 200; k++) temp[k] = 0; for (int i = 0; i < 200; i++) { for (int val = 1; val <= 255; val++) { temp[i] = val; result = check(temp); equal = result % 256; pos = (result - equal) / 256; if (pos >= 1) { key[i] = val; temp[i] = 0; break; } } } }
Generating random numbers into an array which prints to a Txt file. Before hitting the text file, the numbers need to be sorted
so my objective is to basically print out random numbers from 40,000 to 1,000,000 to a txt file, sorted using the heap method. I can print to the text file just fine with random numbers, but I am a bit stuck at sorting them using a heap method. I started a method and got a bit lost half way through after looking at some tutorials. Any thoughts/ helpful comments? Im literally new to stack overflow (posting wise) so forgive me if I didnt place this here correctly. Thank you! //Heapsort algorithm #include <iostream> #include <string> #include <fstream> #include <ctime> #include <stdio.h> #include <stdlib.h> using namespace std; /*class generateDataSet { public: static const int MAX_VALUE = 1000000; public: static const bool SORTED = false; public: static const bool REVERSE_SORTED = false; }; */ int main() { const int array= 16; int arrayNum[array]; srand(time(NULL)); int upB = 1000000; int loB = 40000; int temp; ofstream inputFile; inputFile.open("randomData.txt"); if (inputFile.is_open()) { for (int i = 0; i < array; i++) { arrayNum[i] = (rand()% (upB - loB + 1)) + loB; inputFile << arrayNum[i] << "\n"; } } return 0; } void MaxHeapify(int d[], int i, int n) { int j; int temp; temp = d[i]; j = 2 * 1; while (j <= n) { if (j < n && d[j + 1] > d[j]) j = j + 1; if (temp > d[j]) break; else if (temp <= d[j]) { d[j / 2] = d[j]; j = 2 * j; } } } void heapSort(int d[], int n) { int i; int temp; for (i = n; i >= 2; i); }
Euler's Totient function permutation
I was doing this problem on SPOJ. www.spoj.com/problems/TIP1. I have written this code but I am getting time limit exceeded when judged. Can anyone help me with any optimization or a better approach. if N is a positive integer, then PHI(N) is the number of integers K for which GCD(N, K) = 1 and 1 ≤ K ≤ N. We denote GCD the Greatest Common Divisor. For example, we have PHI(9)=6. #include<iostream> #include<vector> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; #define N 10000010 #define MAXN 10000010 int phi[MAXN + 1], prime[MAXN/10], sz=0; vector<bool> mark(MAXN + 1); int ans[10000011]; vector<int> a(10); vector<int> b(10); bool isprm(long int x) { for(int s=0; s<10; s++) { a[s]=b[s]=0; } long int y=phi[x]; int i=0,j=0; while(x>0) { int rem=x%10; x=x/10; a[i]=rem; i++; } while(y>0) { int rem=y%10; y=y/10; b[j]=rem; j++; } sort(a.begin(), a.end()); sort(b.begin(), b.end()); if(i!=j) return false; for(int s=0; s<10; s++) { if(a[s]!=b[s]) return false; } return true; } void precompute_again() { for(int i=0; i<=20; ++i) ans[i]=0; ans[21]=21; for(long int i=22; i<10000005; ++i){ bool chk=false; chk=isprm(i); if(chk==true) { if(i*phi[ans[i-1]]==phi[i]*ans[i-1]) { ans[i]=i; } else { if(i*phi[ans[i-1]]>phi[i]*ans[i-1]) { ans[i]=ans[i-1]; } else { ans[i]=i; } } } else { ans[i]=ans[i-1]; } } } int main() { phi[1] = 1; for (int i = 2; i <= MAXN; i++ ){ if(!mark[i]){ phi[i] = i-1; prime[sz++]= i; } for (int j=0; j<sz && prime[j]*i <= MAXN; j++ ){ mark[prime[j]*i]=1; if(i%prime[j]==0){ int ll = 0;int xx = i; while(xx%prime[j]==0) { xx/=prime[j]; ll++; } int mm = 1; for(int k=0;k<ll;k++)mm*=prime[j]; phi[i*prime[j]] = phi[xx]*mm*(prime[j]-1); break; } else phi[i*prime[j]] = phi[i]*(prime[j]-1 ); } } precompute_again(); int t; scanf("%d",&t); while(t--) { long int m; scanf("%ld",&m); cout<<ans[m]<<endl; } return 0; }
Try to use a variant of Sieve of Eratosthenes. The following code computes all phi[N] up to MAXN. For MAXN = 1e7 it runs in the blink of an eye. int i, j; int * phi = new int [MAXN]; for (i = 1; i < MAXN; i ++) phi[i] = i; for (i = 2; i < MAXN; i ++) { if (phi[i] != i) continue; for (j = i; j < MAXN; j += i) phi[j] = phi[j] / i * (i - 1); }