I'm tying to implement Kriskal's algorithm in C++ but...
Unhandled exception at 0x0127160d in DAA.exe: 0xC0000005: Access violation reading location 0xdd2021d4.
It stop on this line in getRoot function:
while(cities[root].prev != NO_PARENT)
I think that the problem is with data in cities array. When I prinf all data in array it's not what I want to be. The names of cities are like this "════════════════¤¤¤¤ллллллллю■ю■" and numbers (int) - like this (-842150451). Below is full code.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define NO_PARENT -1
struct city {
char name[11];
int prev;
};
struct path {
unsigned i, j, price;
};
bool comparsion(path p1, path p2) {
return p1.price > p2.price;
}
int getRoot(city *cities, int cityNumber) {
int root = cityNumber, tmp;
while(cities[root].prev != NO_PARENT)
root = cities[root].prev;
while(cityNumber != root) {
tmp = cityNumber;
cityNumber = cities[cityNumber].prev;
cities[tmp].prev = root;
}
return root;
}
bool isListed(city *cities, int n, char cityName[]) {
for(int i = 0; i < n; i++)
if(strcmp(cities[i].name, cityName))
return true;
return false;
}
int getCityNumber(city *cities, int n, char cityName[]) {
for(int i = 0; i < n; i++)
if(strcmp(cities[i].name, cityName))
return i;
return NO_PARENT;
}
int minPrice(city *cities, path *paths, int cityCount, int pathCount) {
unsigned minPrice = 0;
// sort paths by price
std::sort(paths, &paths[pathCount-1], comparsion);
for(int k = 0; k < pathCount; k++) {
printf("path: %d - %d\n", paths[k].i, paths[k].j);
int c1 = getRoot(cities, paths[k].i), c2 = getRoot(cities, paths[k].j);
if(c1 != c2) {
minPrice += paths[k].price;
cities[c2].prev = c1;
}
}
return minPrice;
}
int main() {
int n, m, k;
do {
scanf("%d %d %d", &n, &m, &k);
} while(n < 2 || n > 10001 || m < -1 || m > 100001 || k < -1 || k > 100001);
city* cities = (city*)malloc(n*sizeof(city));
path* paths = (path*)malloc((m + k)*sizeof(path));
int addCities = 0;
char city1[11], city2[11];
for(int i = 0; i < (m + k); i++) {
scanf("%s %s", city1, city2);
if(addCities < n && !isListed(cities, n, city1)) { // if city1 is not into cities
// add it
strcpy(cities[addCities].name, city1);
cities[addCities].prev = NO_PARENT;
addCities++;
}
paths[i].i = getCityNumber(cities, n, city1); // number of city1
if(addCities < n && !isListed(cities, n, city2)) { // if city2 is not into cities
// add it
strcpy(cities[addCities].name, city2);
cities[addCities].prev = NO_PARENT;
addCities++;
}
paths[i].j = getCityNumber(cities, n, city1); // number of city2
if(i >= m)
scanf("%d", &paths[i].price);
}
for(int i = 0; i < (m + k); i++)
printf("%s: %d\n", cities[i].name, cities[i].prev);
// Calculate min price
printf("%d ", minPrice(cities, paths, n, k + m));
system("pause");
return 0;
}
In isListed() and getCityNumber() you use strcmp() to check string equality. There's two problems with the way you're doing it:
strcmp returns 0 when two strings are equal, therefore you need to check if( strcmp(...) == 0 ). It's one of these weird things in C.
After malloc'ing you need to set cities[i].name to something e.g. "unnamed" or just "\0". Otherwise, strcmp will get called on uninitialised strings - and if they don't contain a null character within 11 chars, it will fail. Add this code after the malloc lines:
for( int i = 0 ; i < n ; ++ i ) {
cities[ i ].name[ 0 ] = '\0';
cities[ i ].parent = NO_PARENT;
}
you have to initialize the "cities". There are (m+k) paths between n cities but this doesn't necessarily means that all n cities are included in these paths, since you have set the prev member of a city to NO_PARENT whenever it's listed as city1 or city2, when a city is never listed as those its prev member would be undefined and when you use it as an index in getRoot function while(cities[root].prev != NO_PARENT)
root = cities[root].prev; this would cause the problem.
Related
Please help me to solve the query that this code runs infinitely at a particular line.
It does not give any output as at the end of the code I write the code to print the vector. Even after I assign any value to vector "result" manually still it is not giving any output. why is it so?
#include<bits/stdc++.h>
using namespace std;
bool authorize(int strValue, int value, int M)
{
long int newValue = (strValue - (value * 131) % M);
if (newValue >= 48 && newValue <= 57)
return true;
if (newValue > 65 && newValue <= 90)
return true;
if (newValue >= 97 && newValue <= 122)
return true;
return false;
}
int hashingfunct(string str, int M)
{
long int P, F, sum = 0;
int len = str.length();
for (int i = 0; i < len; i++)
{
P = pow(131, len - i - 1);
F = (int)str[i];
sum += (F * P) % M;
}
sum = sum % M;
return sum;
}
int main()
{
int n = 5;
string str1, str2;
vector<vector<string> > events;
for (int i = 0; i < n; i++) {
cin >> str1 >> str2;
vector<string > temp;
temp.push_back(str1);
temp.push_back(str2);
events.push_back(temp);
}
for (int i = 0; i < n; i++) {
cout << events[i][0] << events[i][1];
}
/*
INPUT FORMAT:
setpassword 1
setpassword 2
setpassword 3
authorize 49
authorize 50
*/
vector<int> result;
int j = 0;
long int m = pow(10, 9);
long int M = m + 7;
long int value, strValue;
for (int i = 0; i < events.size(); i++)
{
strValue = stoi(events[i][1]);
if (events[i][0] == "setPassword") {
value = hashingfunct(events[i][1], M);
}
else if (strValue == value)
result[j++] = 1;
else if (authorize(strValue, value, M))
result[j++] = 1;
else
result[j++] = 0;
}
for (int i = 0; i < result.size(); i++) {
cout << result[i];
}
}
Your program has complete Undefined Behaviour.
Let's get started with the first problem. In the following check code
long int value, strValue; // not initialised
for (int i = 0; i < events.size(); i++)
{
// ...
// here it should have been "setpassword" (i.e. all are small letters)
if (events[i][0] == "setPassword")
{
// if the check fails the `value` never get initialised!
value = hashingfunct(events[i][1], M);
}
// If the `value` not been initialised, check happens with any garbage value here!
else if (strValue == value)
// ...other code
}
You are checking whether the string is "setPassword" instead of "setpassword" (i.e. see in the events vector, all the strings are small letters).
If that goes wrong, the value will never get initialized, meaning it holds any garbage value and hence conducting this check else if (strValue == value) can cause any behaviour to your program (aka Undefined Behaviour).
Secondly, the vector<int> result; is empty at the beginning. Therefore accessing elements via std::vector::operator[] later
result[j++] = 1;
// ...
result[j++] = 1;
// ...
result[j++] = 0;
triggers the access out of bounds (UB). There you need just result.emplace_back(/*value*/); or result.push_back(/*value*/);, and no need of redutant variable j.
In short, you need
#include <iostream>
#include <vector>
#include <string>
// ..other functions
int main()
{
std::vector<std::vector<std::string> > events {
{"setpassword", "1"}, // can be also user input, like in your example
{"setpassword", "2"},
{"setpassword", "3"},
{"authorize", "49" },
{"authorize", "50" }
};
std::vector<int> result;
const long int M = pow(10, 9) + 7;
long int value{ 0 }, strValue{ 0 }; // default initialization
for (const std::vector<std::string> row: events) // better use range-based loop
{
strValue = std::stoi(row[1]);
if (row[0] == "setpassword") {
value = hashingfunct(row[1], M);
if (strValue == value)
result.emplace_back(1);
else if (authorize(strValue, value, M))
result.emplace_back(1);
}
else
result.emplace_back(0);
}
}
As a side note,
Please do not use using namespacestd;
Why should I not #include <bits/stdc++.h>?
Corrected code
#include<bits/stdc++.h>
using namespace std;
bool authorize(long int strValue,long int value,int M){
long int value1=value*131;
long int newValue=(strValue-(value1%M))%M;
if(newValue>=48 && newValue<=57)
return true;
if(newValue>=65 && newValue<=90)
return true;
if(newValue>=97 && newValue<=122)
return true;
return false;
}
int hashingfunct(string str,int M){
long int P,F,sum=0;
int len=str.length();
for(int i=0;i<len;i++){
P=pow(131,len-i-1);
F=(int)str[i];
sum+=(F*P)%M;
}
sum=sum%M;
return sum;
}
int main(){
int n=5;
string str1,str2;
vector<vector<string> > events;
for (int i=0;i<n;i++){
cin>>str1>>str2;
vector<string > temp;
temp.push_back(str1);
temp.push_back(str2);
events.push_back(temp);
}
/*
setPassword cAr1
authorize 223691457
authorize 303580761
setPassword d
authorize 100
*/
vector<int> result;
int j=0;
long int m=pow(10,9);
long int M=m+7;
long int value,strValue;
for(int i=0;i<events.size();i++){
if(events[i][0]=="setPassword"){
value=hashingfunct(events[i][1],M);
continue;
}
strValue=stoi(events[i][1]);
if(strValue==value)
result.push_back(1);
else if(authorize(strValue,value,M))
result.push_back(1);
else
result.push_back(0);
}
for(int i=0;i<result.size();i++){
cout<<result[i];
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am trying to solve an algorithm problem (MST with Kruskal algorithm). It works sometimes and doesn't work sometimes (with runtime error). I solved this problem with another approach, but I want to figure out what is wrong with this code for future problems. I guess it is the memory problem, but I can't find out for two days.
typedef struct edges
{
struct edges *nextNode;
int weight;
int src;
int dest;
}EDGES;
typedef struct vertex
{
EDGES *edgePtr;
int verNum;
int weight;
COLOR color;
}VERTEX;
typedef struct setTree
{
struct setTree *parent;
int verNum;
int rank;
}SETNODE;
SETNODE *findSet(SETNODE *tree)
{
if (tree != tree->parent)
tree->parent = findSet(tree->parent);
return tree->parent;
}
void makeSet(SETNODE *tree, int vernum)
{
tree->parent = tree;
tree->verNum = vernum;
tree->rank = 0;
}
int linkSet(SETNODE *x, SETNODE *y)
{
SETNODE *x_root = findSet(x);
SETNODE *y_root = findSet(y);
if (x_root->rank > y_root->rank)
y_root->parent = x_root;
else if (x_root->rank < y_root->rank)
{
x_root->parent = y_root;
}
else
{
y_root->parent = x_root;
++x_root->rank;
}
return 1;
}
int unionSet(SETNODE *x, SETNODE *y)
{
return linkSet(x, y);
}
void MST_Kruskal(VERTEX **graph, int N, EDGES **edgeList, int edgeNum)
{
SETNODE *set[MAXN];
EDGES *result[MAXN*(MAXN - 1)];
EDGES *tmp[MAXN];
int edgeCnt = 0;
int tmpVerNum1, tmpVerNum2;
for (int i = 0; i < N; ++i)
{
set[i] = new SETNODE;
}
for (int i = 0; i < N; ++i)
{
makeSet(set[i], (i + 1));
}
mergeSort(edgeList, tmp, 0, edgeNum - 1);
/*for (int i = 0; i < edgeNum; ++i)
printf("%d->%d : %d\n", edgeList[i]->src, edgeList[i]->dest, edgeList[i]->weight);
*/
for (int i = 0; i < edgeNum; ++i)
{
tmpVerNum1 = edgeList[i]->src; tmpVerNum2 = edgeList[i]->dest;
if (findSet(set[tmpVerNum1 - 1]) != findSet(set[tmpVerNum2 - 1]))
{
int success = unionSet(set[tmpVerNum1 - 1], set[tmpVerNum2 - 1]);
if (success)
result[edgeCnt++] = edgeList[i];
}
}
printf("%d\n", edgeCnt);
for (int i = 0; i < edgeCnt; ++i)
{
printf("%d %d %d\n", result[i]->src, result[i]->dest, result[i]->weight);
}
for (int i = 0; i < N; ++i)
{
delete set[i];
}
}
For mergeSort, there's some kind of restriction with this problem that if weight is same between edges, there should be less vertex number first.
void merge(EDGES **arr, EDGES **tmp, int left, int middle, int right)
{
int i = left, j = middle + 1, k = left, l;
while (i <= middle && j <= right)
{
if (arr[i]->weight < arr[j]->weight)
{
tmp[k++] = arr[i++];
}
else if (arr[i]->weight == arr[j]->weight)
{
if (arr[i]->src < arr[j]->src)
tmp[k++] = arr[i++];
else if (arr[i]->src == arr[j]->src)
{
if (arr[i]->dest <= arr[j]->dest)
tmp[k++] = arr[i++];
else
tmp[k++] = arr[j++];
}
else
tmp[k++] = arr[j++];
}
else
{
tmp[k++] = arr[j++];
}
}
if (i > middle)
{
for (l = j; l <= right; l++)
{
tmp[k++] = arr[l];
}
}
else
{
for (l = i; l <= middle; l++)
{
tmp[k++] = arr[l];
}
}
for (l = left; l <= right; l++)
{
arr[l] = tmp[l];
}
}
void mergeSort(EDGES **arr, EDGES **tmp, int left, int right)
{
int middle = (left + right) / 2;
if (left < right)
{
mergeSort(arr, tmp, left, middle);
mergeSort(arr, tmp, middle + 1, right);
merge(arr, tmp, left, middle, right);
}
}
I think the problem lies in the declaration of tmp array. You have used it as a temporary array for the merge function in mergeSort.
I am assuming maxN is the maximum number of vertices in the graph. Hence the maximum number of edges in the graph can be maxN*(maxN-1). You have declared the size of result to be that and not tmp when infact the size of result should be maxN (maxN-1 to be precise since it will consist of edges representing a MST at the end) and the size of tmp should be maxN*(maxN-1) since the size of edgeList (which is being sorted using tmp array), i.e., edgeNum can be anywhere between 0 and maxN*(maxN-1).
In general, the fewer pointers you use means you are less likely to run into memory problems. Make sure that you aren't accidentally accessing members of a nullptr, or forgetting to pass an address to a function. It would be helpful if you could give us more information on the error :)
Here is an implementation of Kruskal that I wrote a while back. It makes heavy use of the STL and no pointers while simulating a linked list for the EdgeList using a pre-allocated array:
#include <cstdio>
#include <vector>
#include <queue>
#include <functional>
#include <algorithm>
const int MAXSZ = 1010;
struct Edge
{
static int cnt;
int from, to, weight, next;
} edges[MAXSZ * 2], full[MAXSZ * 2];
int Edge::cnt = 1;
int head[MAXSZ]; // for EdgeList impl
int bigb[MAXSZ]; // for DisjointSet impl
int find(const int c) // DisjointSet `find`
{
if (bigb[c] == c)
return c;
bigb[c] = find(bigb[c]);
return bigb[c];
}
void addEdge(const int a, const int b, const int w) // add edges to EdgeList from pure data
{
edges[Edge::cnt].from = a;
edges[Edge::cnt].to = b;
edges[Edge::cnt].weight = w;
edges[Edge::cnt].next = head[a];
head[a] = Edge::cnt;
++Edge::cnt;
bigb[find(a)] = bigb[find(b)] = std::min(find(a), find(b)); // needed to init DisjointSet
}
void addEdge(const Edge &base) // copy insert to EdgeList
{
edges[Edge::cnt] = base;
edges[Edge::cnt].next = head[base.from];
head[base.from] = Edge::cnt;
++Edge::cnt;
bigb[find(base.from)] = bigb[find(base.to)] = std::min(find(base.from), find(base.to));
}
int main()
{
int m, n;
scanf("%d%d", &m, &n);
auto cmp = [](const int &l, const int &r) { return full[l].weight > full[r].weight; };
std::priority_queue<int, std::vector<int>, std::function<bool(int, int)> > pq(cmp); // Used for kruskal
/* input */
for (int i = 1; i <= n; ++i)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
full[i].from = a;
full[i].to = b;
full[i].weight = w;
pq.push(i);
bigb[full[i].from] = full[i].from;
bigb[full[i].to] = full[i].to;
}
int sum = 0;
for (int vis = 0; !pq.empty(); pq.pop())
{
auto cur = full[pq.top()];
if (find(cur.to) == vis && find(cur.from) == vis)
continue; // if it leads back to something we already have
addEdge(cur);
addEdge(cur.to, cur.from, cur.weight); // other direction
vis = std::min(find(cur.to), find(cur.from));
printf("%d -> %d, %d\n", cur.from, cur.to, cur.weight);
sum += cur.weight;
//debug*/ for (int i=1; i<=m; ++i) printf("%3d", i); printf("\n"); for (int i=1; i<=m; ++i) printf("%3d", bigb[i]); printf("\n\n");
}
printf("total: %d\n", sum);
return 0;
}
/* test data
first line: verticies, edges
next #edges lines: from, to, weight
3 3
1 2 3
3 2 1
3 1 2
5 6
1 2 2
1 4 1
2 3 2
3 4 -2
3 5 1
4 5 9
*/
I have to make a code where the user inputs altitude readings and the code is supposed to output total climb, total descent, and net change. This is what I have below. I can't figure out how to code to have it output what I want it to.
#include <iostream>
using namespace std;
int main()
{
int array[2010], n, c, d, swap; //the array
printf("Enter number of elements\n");
scanf("%d", &n);
printf("Enter %d integers\n", n);
for (c=0; c < n; c++)
scanf("%d", &array[c]);
for (c=0 ; c < ( n - 1 ); c++)
{
for (d = 0 ; d < n - c - 1; d++)
{
if (array[d] > array[d+1]) /* For decreasing order use < */
{
swap = array[d];
array[d] = array[d+1];
array[d+1] = swap;
}
}
}
printf("Sorted list in ascending order:\n"); //lists in order
for ( c = 0 ; c < n ; c++ )
printf("%d\n", array[c]);
// Returns minimum difference between any pair
int findMinDiff(int arr[2010], int n); //supposed to find differce
{
// Initialize difference as infinite
int diff = INT_MAX;
// Find the min diff by comparing difference
// of all possible pairs in given array
for (int d=0; d<n-1; d++)
for (int j=d+1; j<n; j++)
if (abs(array[d] - array[d--]) < diff)
diff = abs(array[d] - array[d--]);
cout<<"Total Climb "<<diff<<endl;
}
system("pause");
return 0;
}
I don't see why you are sorting the array. Sorting the array may cause problems in calculating the "total climb" and "total descent".
My understanding is that this assignment is about calculating the difference between two numbers and processing that difference.
void Process_Data(int array[2010], unsigned int quantity_of_climbs)
{
int total_climb = 0;
int total_descent = 0;
int minimum_change = INT_MAX;
for (int i = 0; i < quantity_of_climbs - 1; ++i)
{
const int height_change = array[i] - array[i+1];
if (height_change > 0) // A "climb"
{
total_climb += height_change;
}
if (height_change < 0) // A "descent"
{
total_descent = (-1) * height_change; // Change from negative to positive.
}
const int abs_height_change = abs(height_change);
if (abs_height_change < minimum_change)
{
minimum_change = abs_height_change;
}
}
// Display results
}
I need a way to solve the classic 5SUM problem without hashing or with a memory efficient way of hashing.
The problem asks you to find how many subsequences in a given array of length N have the sum equal to S
Ex:
Input
6 5
1 1 1 1 1 1
Output
6
The restrictions are:
N <= 1000 ( size of the array )
S <= 400000000 ( the sum of the subsequence )
Memory usage <= 5555 kbs
Execution time 2.2s
I'm pretty sure the excepted complexity is O(N^3). Due to the memory limitations hashing doesn't provide an actual O(1) time.
The best I got was 70 points using this code. ( I got TLE on 6 tests )
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#define MAX 1003
#define MOD 10472
using namespace std;
ifstream in("take5.in");
ofstream out("take5.out");
vector<pair<int, int>> has[MOD];
int v[MAX];
int pnt;
vector<pair<int, int>>::iterator it;
inline void ins(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val) {
has[pnt].push_back({val, 1});
sort(has[pnt].begin(), has[pnt].end());
return;
}
it->second++;
}
inline int get(int val) {
pnt = val%MOD;
it = lower_bound(has[pnt].begin(), has[pnt].end(), make_pair(val, -1));
if(it == has[pnt].end() || it->first != val)
return 0;
return it->second;
}
int main() {
int n,S;
int ach = 0;
int am = 0;
int rez = 0;
in >> n >> S;
for(int i = 1; i <= n; i++)
in >> v[i];
sort(v+1, v+n+1);
for(int i = n; i >= 1; i--) {
if(v[i] > S)
continue;
for(int j = i+1; j <= n; j++) {
if(v[i]+v[j] > S)
break;
ins(v[i]+v[j]);
}
int I = i-1;
if(S-v[I] < 0)
continue;
for(int j = 1; j <= I-1; j++) {
if(S-v[I]-v[j] < 0)
break;
for(int k = 1; k <= j-1; k++) {
if(S-v[I]-v[j]-v[k] < 0)
break;
ach = S-v[I]-v[j]-v[k];
rez += get(ach);
}
}
}
out << rez << '\n';
return 0;
}
I think it can be done. We are looking for all subsets of 5 items in the array arr with the correct SUM. We have array with indexes 0..N-1. Third item of those five can have index i in range 2..N-3. We cycle through all those indexes. For every index i we generate all combinations of two numbers for index in range 0..i-1 on the left of index i and all combinations of two numbers for index in the range i+1..N-1 on the right of index i. For every index i there are less than N*N combinations on the left plus on the right side. We would store only sum for every combination, so it would not be more than 1000 * 1000 * 4 = 4MB.
Now we have two sequences of numbers (the sums) and task is this: Take one number from first sequence and one number from second sequence and get sum equal to Si = SUM - arr[i]. How many combinations are there? To do it efficiently, sequences have to be sorted. Say first is sorted ascending and have numbers a, a, a, b, c ,.... Second is sorted descending and have numbers Z, Z, Y, X, W, .... If a + Z > Si then we can throw Z away, because we do not have smaller number to match. If a + Z < Si we can throw away a, because we do not have bigger number to match. And if a + Z = Si we have 2 * 3 = 6 new combinations and get rid of both a and Z. If we get sorting for free, it is nice O(N^3) algorithm.
While sorting is not for free, it is O(N * N^2 * log(N^2)) = O(N^3 * log(N)). We need to do sorting in linear time, which is not possible. Or is it? In index i+1 we can reuse sequences from index i. There are only few new combinations for i+1 - only those that involve number arr[i] together with some number from index 0..i-1. If we sort them (and we can, because there are not N*N of them, but N at most), all we need is to merge two sorted sequences. And that can be done in linear time. We can even avoid sorting completely if we sort arr at the beginning. We just merge.
For second sequence the merging does not involve adding but removing, but it is very simmilar.
The implementation seems to work, but I expect there is off by one error somewhere ;-)
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
int Generate(int arr[], int i, int sums[], int N, int NN)
{
int p1 = 0;
for (int i1 = 0; i1 < i - 1; ++i1)
{
int ai = arr[i1];
for (int i2 = i1 + 1; i2 < i; ++i2)
{
sums[p1++] = ai + arr[i2];
}
}
sort(sums, sums + p1);
return p1;
}
int Combinations(int n, int sums[], int p1, int p2, int NN)
{
int cnt = 0;
int a = 0;
int b = NN - p2;
do
{
int state = sums[a] + sums[b] - n;
if (state > 0) { ++b; }
else if (state < 0) { ++a; }
else
{
int cnta = 0;
int lastA = sums[a];
while (a < p1 && sums[a] == lastA) { a++; cnta++; }
int cntb = 0;
int lastB = sums[b];
while (b < NN && sums[b] == lastB) { b++; cntb++; }
cnt += cnta * cntb;
}
} while (b < NN && a < p1);
return cnt;
}
int Add(int arr[], int i, int sums[], int p2, int N, int NN)
{
int ii = N - 1;
int n = arr[i];
int nn = n + arr[ii--];
int ip = NN - p2;
int newP2 = p2 + N - i - 1;
for (int p = NN - newP2; p < NN; ++p)
{
if (ip < NN && (ii < i || sums[ip] > nn))
{
sums[p] = sums[ip++];
}
else
{
sums[p] = nn;
nn = n + arr[ii--];
}
}
return newP2;
}
int Remove(int arr[], int i, int sums[], int p1)
{
int ii = 0;
int n = arr[i];
int nn = n + arr[ii++];
int pp = 0;
int p = 0;
for (; p < p1 - i; ++p)
{
while (ii <= i && sums[pp] == nn)
{
++pp;
nn = n + arr[ii++];
}
sums[p] = sums[pp++];
}
return p;
}
int main() {
ifstream in("take5.in");
ofstream out("take5.out");
int N, SUM;
in >> N >> SUM;
int* arr = new int[N];
for (int i = 0; i < N; i++)
in >> arr[i];
sort(arr, arr + N);
int NN = (N - 3) * (N - 4) / 2 + 1;
int* sums = new int[NN];
int combinations = 0;
int p1 = 0;
int p2 = 1;
for (int i = N - 3; i >= 2; --i)
{
if (p1 == 0)
{
p1 = Generate(arr, i, sums, N, NN);
sums[NN - 1] = arr[N - 1] + arr[N - 2];
}
else
{
p1 = Remove(arr, i, sums, p1);
p2 = Add(arr, i + 1, sums, p2, N, NN);
}
combinations += Combinations(SUM - arr[i], sums, p1, p2, NN);
}
out << combinations << '\n';
return 0;
}
I have list of pair [x;y] where x is unique and y can be duplicate(integers).
Here lies a problem:
Given a pair [x;y], find new pair [k;m], such that:
k > x
m >= y
k - x is minimized.
Now, I've solved this problem with this logic; I sort pairs by x, and then start naive O(n^2) algorithm on it. It seems to work fine, except it's too slow.
Can I do better?
The actual problem im trying to solve, is here: http://www.spoj.com/problems/VBOSS/
and my current code:
#include <stdio.h>
#include <utility>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
struct employee
{
int id;
int salary;
int height;
int parent_index;
int sub_ordinates;
int cur;
bool important;
bool operator < (const employee& e) const
{
if(height == e.height)
return salary > e.salary;
return (height > e.height);
}
};
// problem states explictly that no two employees
// have same salary.
struct salary_predicate
{
inline bool operator() (const employee& struct1, const employee& struct2)
{
return (struct1.salary > struct2.salary);
}
};
const int MAX_EMPLOYEES = 30000;
const int MAX_QUERIES = 200;
employee employees[MAX_EMPLOYEES];
int queries[MAX_QUERIES];
int main()
{
int test_cases;
scanf("%d", &test_cases);
while(test_cases--)
{
int employeeCount, queryCount;
scanf("%d %d", &employeeCount, &queryCount);
int i = 0;
int j = 0;
while(i < employeeCount)
{
employees[i].parent_index = -1;
employees[i].sub_ordinates = 0;
employees[i].cur = i;
employees[i].important = false;
scanf("%d %d %d", &employees[i].id, &employees[i].salary, &employees[i].height);
i++;
}
map<int, int> mapper;
while(j < queryCount)
{
scanf("%d", &queries[j]);
mapper.insert(pair<int, int>(queries[j], -1));
j++;
}
// now step1; sort employees structure
// based on SALARY!!
sort(employees, employees + employeeCount, salary_predicate());
for(int k = 0; k < employeeCount; k++)
{
employees[k].cur = k;
if(mapper.find(employees[k].id) != mapper.end())
{
mapper[employees[k].id] = k;
employees[k].important = true;
}
}
int found = 0;
for(int l = employeeCount - 1; l >= 0; l--)
{
int gef = l - 1;
// check out information about previous worker,
// he might give us some valuable information!
// with his help, we know if we can skip some shit :)
if(l + 1 < employeeCount && employees[l + 1].parent_index != -1)
{
// if previous employee is smaller than our current employee
// then we can skip some people, becase we know that answer cant be
// smalle than that :)
if(employees[l + 1].height <= employees[l].height)
gef = employees[l + 1].parent_index - 1;
}
// find boss!
for(int b = gef; b >= 0; b--)
{
if(employees[b].height >= employees[l].height)
{
employees[l].parent_index = b;
employees[b].sub_ordinates += employees[l].sub_ordinates + 1;
break;
}
}
// this bit makes sure if we have processed all necessay things,
// then we can basically stop our work.
if(employees[l].important) found++;
if(found == mapper.size()) break;
}
// time to print it out.
for(int b = 0; b < queryCount; b++)
{
int id = queries[b];
int index = mapper[id];
int parent_index = employees[index].parent_index;
int parent = parent_index < 0 ? 0 : employees[parent_index].id;
printf("%d %d\r\n", parent, employees[index].sub_ordinates);
}
}
return 0;
}
salary=x, and height=y.
I would start by eliminating all records where m<y or k<=x. Then find the item with the smallest k value out of what's left. Both of these should be linear, so your overall complexity should also be linear.
struct p {
int k, m;
};
p find_item(p xy, std::vector<p> &values) {
auto end = std::partition(values.begin(), values.end(),
[xy](p const &v) { return xy.k < v.k || xy.m >= v.m; });
return *std::min_element(values.begin(), end,
[](p const &a, p const &b) { return a.k < b.k; });
}