I have partially solved a problem on the UVA judge (see code below), with recursive backtracking/dynamic programming and bitmasking.
This gives the right final answer to the included test cases, however, I must also print the optimal path route, which I am unsure how to save in a recursive routine.
The problem is a travelling salesman problem, basically the problem is this:
Given n coordinates, find the shortest path between all these coordinates.
#include<iostream>
#include<cmath>
#include<climits>
#include<cstdio>
using namespace std;
#define MAX_N 10
struct Computer{
double x;
double y;
};
Computer computers[MAX_N];
double dist[MAX_N][MAX_N];
double DP[MAX_N][1 << MAX_N];
size_t n;
double d(Computer a, Computer b) {
return sqrt(pow((a.x - b.x), 2.0) + pow((a.y - b.y), 2.0)) + 16.0;
}
double recurse(int i, int switched)
{
if(switched == (1 << n) - 1) return 0;
if(DP[i][switched] != 0) return DP[i][switched];
double local_min = INT_MAX;
for(int j = 0; j < n; j++)
if(i != j && !(switched & (1 << j)))
local_min = min(dist[i][j] + recurse(j, switched | (1 << j)), local_min);
return DP[i][switched] = local_min;
}
int main()
{
for(unsigned int p = 1; cin >> n; p++) {
if(n == 0) return 0;
memset(DP, 0, sizeof DP);
for(size_t i = 0; i < n; ++i) {
Computer c; cin >> c.x >> c.y;
computers[i] = c;
}
for(size_t i = 0; i < n; ++i) for(size_t j = 0; j < n; ++j)
dist[i][j] = d(computers[i], computers[j]);
printf("%d: %.2f\n", p, recurse(0, 1));
}
}
A common way of storing the path is to keep track of an additional map that stores the node the pathfinder took to get to the current point. When you've found the optimal route to the end node, you can then query this map until you are back at the starting node.
Collecting the optimal path in one-player puzzles is a similar problem as saving the principal variation in two-player games such as chess. See this link on how to implement it.
The idea is to store a pointer to a vector/array of steps (moves in chess), and to update that array whenever your backtracking algorithm finds an improvement on the shortest path so far.
Related
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.
One day, Twilight Sparkle is interested in how to sort a sequence of
integers a1, a2, ..., an in non-decreasing order. Being a young
unicorn, the only operation she can perform is a unit shift. That is,
she can move the last element of the sequence to its beginning:
a1, a2, ..., an → an, a1, a2, ..., an - 1. Help Twilight Sparkle to
calculate: what is the minimum number of operations that she needs to
sort the sequence?
Input
The first line contains an integer n (2 ≤ n ≤ 105). The second
line contains n integer numbers a1, a2, ..., an (1 ≤ ai ≤ 105).
Output
If it's impossible to sort the sequence output -1. Otherwise
output the minimum number of operations Twilight Sparkle needs to sort
it.
Examples
input
2
2 1
output
1
input
3
1 3 2
output
-1
input
2
1 2
output
0
Above is the problem and now I am confused because the solution down there used a variable called "s" and played around it for some reason but I don't know why was that variable used, if someone can tell me I'll be thankful.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, s, v(0);
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n - 1; i++) if (a[i] > a[i + 1]) s = i, v++;
if (a[n - 1] > a[0]) s = n - 1, v++;
if (v == 0) cout << 0 << endl;
else if (v > 1) cout << -1 << endl;
else cout << n - 1 - s << endl;
return 0;
}
Now here is my own solution, it works and everything except on a 10^5(and around that) size array but the question time limit is only 1000 ms, and mine exceeds that limit due to the nested loops making it go over O(10^8) which is 1000 ms on their systems.
#include <bits/stdc++.h>
#define fl(i,n) for(int i = 0; i < n; i++)
#define ll long long
#define nl endl
#define pb push_back
#define mp make_pair
#define PII pair<int,int>
#define EPS 1e-9
#define INF 1e9
using namespace std;
bool check(int a[], int n){
for(int i = 0; i < n-1; i++){
if(a[i] <= a[i+1]) continue;
return false;
}
return true;
}
int main()
{
int n;
cin >> n;
int a[n]; //is out of standard i know but it's accepted in the contest's compiler so we just use it
for(int i = 0; i < n; i++){
cin >> a[i];
}
if(check(a,n)){
cout << 0;
return 0;
}
int ret = 0;
for(int i = 0; i < n-1; i++){
ret++;
for(int j = n-1; j > 0; j--)
a[j] ^= a[j-1] ^= a[j] ^= a[j-1]; //is xor swap
if(check(a,n)){
cout << ret;
return 0;
}
}
cout << -1;
return 0;
}
PS: I TRACED the solution's code and even if I get the correct answers I simply don't know what it refers to.
The other person's implementation relies on an algorithmic insight. The only way a sequence can be sorted by moving back to front is if the sequence is made of two already-sorted sections. Then, the goal is to check how many unsorted discontinuities exist, and where they are. That's what s appears to be used for: the index of the (last) discontinuity of the sequence. v is the count of discontinuities.
If there are 0, it's already sorted. If more than 1, it's unsortable. If it's exactly one, then you can easily figure out how many shifts you need to perform to pull the discontinuity back to the front, using it's location (s) in the original sequence.
The only extra line of code is the special case of checking for the discontinuity around end of the sequence.
My recommendation: Generate a larger set of test sequences, and print v and s for each one.
Task:For a given sequence of n numbers, find the substring with a maximum total sum. I created I code in C++ which give correct answers. I would like to know is there any possibility to solve this task with lower computational complexity?
Example input:
20
8973
-4625
-2038
3405
-7004
-9853
-361
3294
4036
8767
1711
-3100
2139
-4993
-9572
3789
2472
-6170
5408
2200
output:
17808
My actual code:
#include<iostream>
#include<cmath>
#include<vector>
#include <algorithm>
using namespace std;
typedef long long int lint;
int main()
{
lint t = 0;
cin >> t;
vector<lint> Ar;
bool st = false;
for (lint i = 0; i < t; i++)
{
lint n = 0;
cin >> n;
if (st == true)Ar.push_back(n);
else if (n>0 && st == false)
{
Ar.push_back(n);
st = true;
}
}
if (Ar.size() == 0)
{
cout << "0" << endl;
}
else
{
vector<lint> Adding;
for (std::size_t i = 0; i < Ar.size(); i++)
{
if (Ar[i] > 0)
{
Adding.push_back(i);
}
}
vector<lint> D;
for (std::size_t j = 0; j < Adding.size(); j++)
{
lint s = 0;
for (std::size_t i = Adding[j]; i < Ar.size(); i++)
{
if (Ar[i] > 0)
{
s += Ar[i];
D.push_back(s);
}
else
{
s += Ar[i];
}
}
}
vector<lint>::const_iterator it2;
// Find max element in the vector
it2 = max_element(D.begin(), D.end());
cout << *it2 << endl;
}
return 0;
}
The best computational complexity to solve this task is linear. Your code on the other hand is not linear and therefor the answer to your question is - yes it is possible to solve the problem with better complexity.
The problem you are solving is known as Maximum subarray problem and is quite famous.
It looks that you went straight into writing code.
The first step would be to think about the problem.
The optimal sequence might include the first number 20. If you examine the numbers from the start, where might the sequence end with an optimal result if it starts with 20? And at which point could you say that any longer sequence that is optimal cannot contain the number 20?
If you look at the sequence and examine it one by one, you will see that 20+8973 might be optimal. Up to 3405 is not optimal but might be the start of an optimal sequence. But with the -9853 it is obvious that an optimal sequence other than 20+8973 must start with the 3294 or later. (Ask yourself why, then turn it into an algorithm).
So I have the following code and I need to derive the execution time growth rate, however I have no idea where to start. My question is, how do I go about doing this? Any help would be appreciated.
Thank you.
// function to merge two sorted arrays
int merge (int smax, char sArray[], int tmax, char tArray[], char target[])
{
int m, s, t;
for (m = s = t = 0; s < smax && t < tmax; m++)
{
if (sArray[s] <= tArray[t])
{
target[m] = sArray[s];
s++;
}
else
{
target[m] = tArray[t];
t++;
}
}
int compCount = m;
for (; s < smax; m++)
{
target[m] = sArray[s++];
}
for (; t < tmax; m++)
{
target[m] = tArray[t++];
}
return compCount;
}
It's actually very simple.
Look, the first for loop increases either s or t at each iteration, so it's O(smax + tmax). The second loop is obviously O(smax), the third is O(tmax). Altogether we get O(smax + tmax).
(There exist some cleverer ways to prove, but I've intentionally left them out.)
All loops are bounded in number of iterations by (smax + tmax). So you could say the algorithm is O( max(smax,tmax) ) or O( smax +tmax).
I'm stuck at an impass with this implementation. My n2 variable is being overwritten during the merging of the subarrays, what could be causing this? I have tried hard-coding values in but it does not seem to work.
#include <iostream>
#include <cstdlib>
#include <ctime> // For time(), time(0) returns the integer number of seconds from the system clock
#include <iomanip>
#include <algorithm>
#include <cmath>//added last nite 3/18/12 1:14am
using namespace std;
int size = 0;
void Merge(int A[], int p, int q, int r)
{
int i,
j,
k,
n1 = q - p + 1,
n2 = r - q;
int L[5], R[5];
for(i = 0; i < n1; i++)
L[i] = A[i];
for(j = 0; j < n2; j++)
R[j] = A[q + j + 1];
for(k = 0, i = 0, j = 0; i < n1 && j < n2; k++)//for(k = p,i = j = 1; k <= r; k++)
{
if(L[i] <= R[j])//if(L[i] <= R[j])
{
A[k] = L[i++];
} else {
A[k] = R[j++];
}
}
}
void Merge_Sort(int A[], int p, int r)
{
if(p < r)
{
int q = 0;
q = (p + r) / 2;
Merge_Sort(A, p, q);
Merge_Sort(A, q+1, r);
Merge(A, p, q, r);
}
}
void main()
{
int p = 1,
A[8];
for (int i = 0;i < 8;i++) {
A[i] = rand();
}
for(int l = 0;l < 8;l++)
{
cout<<A[l]<<" \n";
}
cout<<"Enter the amount you wish to absorb from host array\n\n";
cin>>size;
cout<<"\n";
int r = size; //new addition
Merge_Sort(A, p, size - 1);
for(int kl = 0;kl < size;kl++)
{
cout<<A[kl]<<" \n";
}
}
What tools are you using to compile the program? There are some flags which switch on checks for this sort of thing in e,.g. gcc (e.g. -fmudflap, I haven't used it, but it looks potehtially useful).
If you can use a debugger (e.g. gdb) you should be able to add a 'data watch' for the variable n2, and the debugger will stop the program whenever it detects anything writing into n2. That should help you track down the bug. Or try valgrind.
A simple technique to temporarily stop this type of bug is to put some dummy variables around the one getting trashed, so:
int dummy1[100];
int n2 = r - q;
int dummy2[100];
int L[5], R[5];
Variables being trashed are usually caused by code writing beyond the bounds of arrays.
The culprit is likely R[5] because that is likely the closest. You can look in the dummies to see what is being written, and may be able to deduce from that what is happening.
ANother option is to make all arrays huge, while you track down the problem. Again set values beyond the correct bounds to a known value, and check those values that should be unchanged.
You could make a little macro to do those checks, and drop it in at any convenient place.
I had used the similar Merge function earlier and it doesn't seem to work properly. Then I redesigned and now it works perfectly fine. Below is the redesigned function definition for merge function in C++.
void merge(int a[], int p, int q, int r){
int n1 = q-p+1; //no of elements in first half
int n2 = r-q; //no of elements in second half
int i, j, k;
int * b = new int[n1+n2]; //temporary array to store merged elements
i = p;
j = q+1;
k = 0;
while(i<(p+n1) && j < (q+1+n2)){ //merging the two sorted arrays into one
if( a[i] <= a[j]){
b[k++] = a[i++];
}
else
b[k++] = a[j++];
}
if(i >= (p+n1)) //checking first which sorted array is finished
while(k < (n1+n2)) //and then store the remaining element of other
b[k++] = a[j++]; //array at the end of merged array.
else
while(k < (n1+n2))
b[k++] = a[i++];
for(i = p,j=0;i<= r;){ //store the temporary merged array at appropriate
a[i++] = b[j++]; //location in main array.
}
delete [] b;
}
I hope it helps.
void Merge(int A[], int p, int q, int r)
{
int i,
j,
k,
n1 = q - p + 1,
n2 = r - q;
int L[5], R[5];
for(i = 0; i < n1; i++)
L[i] = A[i];
You only allocate L[5], but the n1 bound you're using is based on inputs q and p -- and the caller is allowed to call the function with values of q and p that allow writing outside the bounds of L[]. This can manifest itself as over-writing any other automatic variables, but because it is undefined behavior, just about anything could happen. (Including security vulnerabilities.)
I do not know what the best approach to fix this is -- I don't understand why you've got fixed-length buffers in Merge(), I haven't read closely enough to discover why -- but you should not access L[i] when i is greater than or equal to 5.
This entire conversation also holds for R[]. And, since *A is passed to Merge(), it'd make sense to ensure that your array accesses for it are also always in bound. (I haven't spotted them going out of bounds, but since this code needs re-working anyway, I'm not sure it's worth my looking for them carefully.)