How to count comparisons in selectionsort?
terms:
when the statements you perform to find the maximum value is 'true'
then count comparison.
The value to get the maximum value is held at the first element in the array, not at random.
I try with C
variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
#include <stdio.h>
int main() {
int sort[10000], i, n, MAX, temp, count;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &sort[i]);
}
for (MAX = 0; MAX < n; MAX++)
for (i = MAX + 1; i < n; i++) {
if (sort[MAX] > sort[i]) {
count++;
temp = sort[MAX];
sort[MAX] = sort[i];
sort[i] = temp;
}
}
printf("%d ", count);
return 0;
}
Sample Input
10
0 7 1 6 7 7 6 6 5 4
Sample Output
17
EDIT: new code:
#include <stdio.h>
#define SWAP(x, y, temp) ( (temp)=(x), (x)=(y), (y)=(temp) )
int count = 0;
void selection_sort(int list[], int n) {
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
if (list[j] < list[least]) {
least = j;
count++;
}
}
SWAP(list[i], list[least], temp);
}
}
int main() {
int list[10000], i, n;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &list[i]);
};
selection_sort(list, n);
printf("%d", count);
}
how about this? why this code didn't move too?
You aren't counting the right thing, this code
if(sort[MAX]>sort[i])
{
count++;
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
counts the times that two numbers are swapped. But you want to count comparisons so it should be this
count++;
if(sort[MAX]>sort[i]) // this is what we are counting
{
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
Another problem is that you don't give count an initial value of zero
int sort[10000],i,n,MAX,temp,count;
should be
int sort[10000],i,n,MAX,temp,count = 0;
how to count comparison selectionsort?
Your definition of the term is oddly worded, but it seems to be intended to focus on the essential comparisons of the algorithm, as opposed to comparisons performed incidentally for other purposes, or inside library functions. That is, in the implementation you present (whose correctness I do not evaluate), you're to count each evaluation of sort[MAX]>first, but not MAX<n or i<n.
You appear to be using variable count for that purpose, but you are counting only comparisons that evaluate to true. My interpretation of the problem, based both on the wording presented and on my general expectations for such a problem, is that every evaluation of sort[MAX]>first should be counted, regardless of the result. That would be achieved by lifting the expression count++ out of the if block, but leaving it inside the inner enclosing for loop.
Of course, as #john observes, you do need to initialize count to 0 before beginning to sort. You might luck into getting that by accident, but the initial value of a local variables without an initializer is indeterminate (at least) until a value is assigned.
i try with c variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
Even with the misplacement of your increment to count, if your sort were in fact working then you would expect to see some counts for most inputs. That you don't is a good sign that your sort in fact does not work correctly. I would suggest outputting also the the sorted results so that you can debug the details of the sort algorithm.
You could abstract out the comparison into a function or macro that also increments a counter. The macro approach could be
#define GT(x,y,counter) (counter++, (x) > (y) ? 1 : 0)
...
if ( GT( sort[MAX], sort[i], count ) == 1 )
{
// perform swap
}
whereas the function approach would be
int gt( int x, int y, int *counter )
{
(*counter)++;
if ( x > y )
return 1;
return 0;
}
...
if ( gt( sort[MAX], sort[i], &count ) == 1 )
{
// perform swap
}
You are counting the number of swaps, not the number of comparisons.
Here is a corrected without a global variable and a few extra checks:
#include <stdio.h>
#define SWAP(x, y, temp) ((temp) = (x), (x) = (y), (y) = (temp))
int selection_sort(int list[], int n) {
int count = 0;
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
count++;
if (list[j] < list[least]) {
least = j;
}
}
SWAP(list[i], list[least], temp);
}
return count;
}
int main() {
int list[10000], i, n, count;
if (scanf("%d", &n) != 1 || n > 10000)
return 1;
for (i = 0; i < n; i++) {
if (scanf("%d", &list[i]) != 1)
return 1;
}
count = selection_sort(list, n);
printf("%d\n", count);
return 0;
}
Not however that your algorithm will always perform the same number of comparisons for any set of n values: n * (n - 1) / 2 comparisons, and since you do not test of i != least, it will perform n - 1 swaps.
Related
I need to find the maximum remainder for n divided by any integer number from 1 to n, and the denominator which this remainder is found with.
In my implementation fun1 works as expected and returns the max remainder, fun2 is supposed to give 3 but its giving 2 .probably mistake is at break statement.
Sample input: 5
Expected output: 2 3.
My output: 2 2.
#include <iostream>
#include <algorithm>
using namespace std;
int fun2(int a);
int fun1(int n ,int num);
int main(){
int n = 0; int num = 0;;
cin >> n;
int p = fun1(n, num);
cout << p << "\n";
cout << fun2(p);
}
int fun1(int n, int num){
int b = 0;
for(int i = 1; i <= n; i++){
num = n % i;
b = max(num, b);
}
return b;
}
int fun2(int n,int p ){
int num = 0; int c = 0; int d = 0;
for(int i = 1; i <= n; i++){
num = n % i;
c = max(num, c);
if(c == p){
break;
}
d = i;
}
return d;
}
Since you already managed to successfully find the biggest remainder, you may get use of this function and return the number this remainder is found with:
std::pair<int, int> biggestRemDem(int value) {
int dm = 1;
int rm = 0;
for(int i = dm; i <= value; ++i){
const auto tmpRm = value % i;
if (tmpRm > rm) {
rm = tmpRm;
dm = i;
}
}
return { rm, dm };
}
The signature of the function needs to return std::pair however, but you no longer need the std::max, so the headers required to include are also changed:
#include <iostream>
#include <utility>
std::pair<int, int> biggestRemDem(int value);
int main(){
int n{};
std::cin >> n;
const auto result = biggestRemDem(n);
std::cout << result.first << " " << result.second << std::endl;
}
In fun2 you have:
if(c == p){
break;
}
d = i;
When you found the right index so that c == p the break will exit the loop and d == i; is not execute. Therefore d has the value from the previous loop, i.e. one less than you need.
Apart from that the code really smells:
fun1
should not have a second argument sum.
should remember the index where if found the largest remainder and you would be done
fun2
the maximum remainder is p, no need to max(num, c). Actually drop the c alltogether and just use num == p
n % 1 == 0 and n % n == 0. The loop will always break with i < n. Might as well not have a conditional: for(int i = 1; ; i++)
you need d because at the end of the loop i disappears. Why not pull i out of the loop? int i; for(i = 1; ; i++)
and now you can use a different conditional again
int fun2(int n,int p ){
int i;
for(i = 1; n % i != p; i++) { }
return i;
}
or
int fun2(int n,int p ){
int i = 1;
for(; n % i != p; i++) { }
return i;
}
or
int fun2(int n,int p ){
int i = 1;
while(n % i != p) ++i;
return i;
}
I need to find the maximum remainder for n divided by any integer number from 1 to n, and the denominator which this remainder is found with.
It seems that the asker decided to solve this in two steps. They wrote a function fun1 returning the maximum remainder and a function fun2, which fed with the previously calculated remainder, returns the corresponding dividend.
While not an efficient approach, it could work if implemented correctly, but that's not the case.
Other than some (very) bad naming choices, we can find:
In the original version of the posted code, fun2 has a function prototype with a single parameter and it is called passing the value returned by fun1, which is the maximum remainder. The problem is that this way the function has no way to know what was the original value of n and actually declares a local n, initialized to zero, so that the body of the loop for(int i = 1; i <= n; i++) is never executed.
The actual version of this question shows a definition of fun2 with two parameters, that can't compile unless both the prototype and the call site are changed accordingly.
Assuming that the original n and the remainder p were succesfully passed to fun2, there still would be another issue:
int fun2(int n, int p ) {
int c = 0, d = 0;
for(int i = 1; i <= n; i++) {
int num = n % i;
c = max(num, c);
if(c == p){ // So, if we reach the passed remainder...
break; // We break out of the loop, skipping...
}
d = i; // this line, meaning...
}
return d; // That the dividend previous to the correct one is returned!
}
They could just return i; when c == p.
The answer by The Dreams Wind presents a much better approach to this task. I'd like to suggest an O(1) solution, though. Consider these points:
The result of n % i can't be equal or greater than i. It's in the range [0, i).
n / 2 is the greatest number that can divide n other than n itself. It means that all the numbers i in (n/2, n) are such that n % i > 0.
For every number i in (n/2, n), we can actually say that n % i = n - i.
So, when n is greater than 2, the i corresponding to the maximum remainder is just 1 + n/2 and said remainder is n - n/2 - 1.
Basically i want to write a function that takes values from 0 to 6 and gives back a random assortment such as 2,3,4,5,0,1,6. Here is the code that i came up with. However the problem is that the integer prev (meaning previous) does not store all the old values of r (random number) and thus some values end up being repeated. How might i fix this?
int s(int b)
{
// b is 7
int h = b-1;
int prev = -1;// to store the previous r value
srand(time(0));
for (int i = 0; i < b; i++)
{
int r = rand()%(h - 0 + 1) + 0;
if (r != prev)
{
cout << r << endl;
prev = r;
}
else if (r == prev)
{
s(b);
}
}
return 0;
}
From the comments, this sounds more like a homework problem than a practical problem because you said "No arrays allowed". But I suppose it is an interesting problem.
Here's some code, in Java with only loops, if statements, and with no arrays, as required.
It outputs a random permutation of the set 0, 1, ..., N, shuffled with the Fisher-Yates algorithm.
void printRandom(int N) {
long used = 0;
for (int i = 0; i < N; i++) {
int randomIndex = ThreadLocalRandom.current().nextInt(N - Long.bitCount(used));
for (int j = 0; j < N; j++) {
if ((used & (1L << j)) == 0) {
if (randomIndex-- == 0) {
System.out.print(j + " ");
used = used | (1L << j);
break;
}
}
}
}
}
It is unfortunately limited to the size of a long on your system :)
I think the best way to solve this problem is by using an aux funtion that stores in a variable all the numbers printed until the moment, check if the new number is in the used numbers variable, if not add it to the variable (you can use strings? I know that they are arrays of char's but maybe you can)
Something like this:
function aux(int b, char *variables_printed, int iterations_left)
if (b = 0) then print variables_printed
else
int n = generate_random_number() %b
while (n in variables_printed)
n= (n+random_number) % b
variables_printed += n
aux(b, variables_printed, iterations_left-1)
And your other function:
function s(b)
if b < 0 return 0
else
char *variables_to_print
aux(b, variables_to_print, b)
If you can not use strings, you can do it with long as konsolas said.
I wrote the following dp code for finding the prime factors of a number.
#include <bits/stdc++.h>
#define max 1000001
using namespace std;
vector <int> prime;
vector<bool> isprime(max,true);
vector<bool> visited(max,false);
vector<int> data(max,-1);
void dp(int n,int last)
{
if(n >= max || visited[n])
return;
visited[n] = true;
for(int i = last;i<prime.size();i++)
{
if(n*prime[i] >= max || data[n*prime[i]] != -1)
return;
data[n*prime[i]] = prime[i];
dp(n*prime[i],i);
}
}
int main()
{
isprime[1] = false;
data[1] = 1;
for(int i = 4;i<max;i += 2)
isprime[i] = false;
for(int i = 3; i*i< max;i += 2)
{
for(int j = i*i; j < max;j += i)
isprime[j] = false;
}
prime.push_back(2);
data[2] = 2;
for(int i =3;i<max;i += 2)
if(isprime[i])
{
prime.push_back(i);
data[i] = i;
}
for(int i = 0;i<prime.size();i++)
{
dp(prime[i],i);
}
cout<<"...1\n";
for(int i = 2;i<=8000;i++)
{
cout<<i<<" :- ";
int temp = i;
while(temp!= 1)
{
cout<<data[temp]<<" ";
temp = temp/data[temp];
}
cout<<endl;
}
return 0;
}
Here, last is the last index of prime number n.
But I am getting segmentation fault for this, when I change max to 10001, it runs perfectly. I'm not getting why is this happening since the data-structures used are 1-d vectors which can hold values up to 10^6 easily.
I checked your program out using GDB. The segfault is taking place at this line:
if(n*prime[i] >= max || data[n*prime[i]] != -1)
In your first ever call to DP in your for loop, where you call dp(2,0), the recursive calls eventually generate this call: dp(92692,2585).
92692 * 2585 = 239608820
This number is larger than a 32 bit integer can hold, so the r-value generated by the integer multiplication of those two numbers overflows and becomes negative. nprime[i] becomes negative, so your first condition of the above loop fails, and the second is checked. data[n * prime[i]] is accessed, and since n*prime[i] is negative, your program accesses invalid memory and segfaults. To fix this, simply change n to a long long in your parameter list and you should be fine.
void dp(long long n, int last)
I'm trying to solve a problem from Codeforces (http://codeforces.com/problemset/problem/189/A)
Here's the problem statement:
Polycarpus has a ribbon, its length is n. He wants to cut the ribbon in a way that fulfils the following two conditions:
After the cutting each ribbon piece should have length a, b or c.
After the cutting the number of ribbon pieces should be maximum.
Help Polycarpus and find the number of ribbon pieces after the required
cutting.
Input
The first line contains four space-separated integers n, a, b and c (1 ≤ n, a, b, c ≤ 4000) — the length of the original ribbon and the acceptable lengths of the ribbon pieces after the cutting, correspondingly. The numbers a, b and c can coincide.
Output
Print a single number — the maximum possible number of ribbon pieces. It is guaranteed that at least one correct ribbon cutting exists.
Sample Input
5 5 3 2
Sample Output
2
I tried to solve this problem using Dynamic Programming (Topdown approach). But I'm not able to get the correct answer. There might be something wrong with the recursive function. Here's my code:
#include<bits/stdc++.h>
using namespace std;
int n,s;
int a[3];
int val,m=-1;
int dp(int n)
{
if(n==0)
return 0;
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
return m;
}
int main()
{
scanf("%d %d %d %d",&n,&a[0],&a[1],&a[2]);
cout<<dp(n)<<endl;
return 0;
}
What is the problem in the above approach?
There are several problems:
Wrong Search
In your lines
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
You should be checking for the maximum of the different vals obtained for the different choices of i.
Wrong Termination
If the length is not 0 and no ribbon can be cut, you should return something like minus infinity. You currently return m which is initially -1 (more on this later). This is wrong, and for long ribbons will essentially ensure that you just choose the minimum of a, b, and c.
Use of Globals
Some globals, e.g., m are initialized once but are modified by the recursion. It's not "just" bad programming habits - it's not doing what you want.
No Reuse
By calling the recursion unconditionally, and not reusing previous calls, your running time is needlessly high.
int main() {
int n, a, b, c;
scanf("%d %d %d %d", &n, &cuts[0], &cuts[1], &cuts[2]);
sort(cuts, cuts + 3);
for (int i = 0; i <= n; i++) {
max_cuts[i] = INT_MIN;
}
max_cuts[0] = 0;
max_cuts[cuts[0]] = 1;
max_cuts[cuts[1]] = 1;
max_cuts[cuts[2]] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 3; j++) {
if (cuts[j] > i) break;
max_cuts[i] = max(max_cuts[i - cuts[j]] + 1, max_cuts[i]);
}
}
printf("%d\n", max_cuts[n]);
return 0;
}
#Ami Tavory correctly suggested the problems with your recursive approach. May be my solution below can help you understand better how to form states and check bounds:
int main()
{
int n, a, b, c;
cin >> n >> a >> b >> c;
const int l = n + 1;
int sum[l];
fill(sum, sum+l, INT_MIN);
sum[0] = 0;
for(int i=1; i<=n; i++)
{
if(i - a >= 0)
{
sum[i] = sum[i-a] + 1;
}
if(i - b >= 0 && sum[i-b] + 1 > sum[i])
{
sum[i] = sum[i-b] + 1;
}
if(i - c >= 0 && sum[i-c] + 1 > sum[i])
{
sum[i] = sum[i-c] + 1;
}
}
cout << sum[n] << endl;
return 0;
}
Simply at each sum[i], we are maximizing the number of cuts. So, at sum[i], we are storing the max(sum[i-a]+1, sum[i-b]+1, sum[i-c]+1).
Other than this, there are just bound checks.
you can solve this problem through top down approach.A dp problem always check all the possible cases then gives us the optimal solution.so here is the code
#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int DP[4001];
int solve(int n){
if(n == 0)return 0;
if(n<0) return INT_MIN;
if(DP[n] != -1)return DP[n];
else{
DP[n] = max(1+solve(n-a),max(1+solve(n-b),1+solve(n-c)));
return DP[n];
}
}
int main(){
int n,x;
cin>>n>>a>>b>>c;
for(int i = 0;i<4001;++i){
DP[i] = -1;
}
x = solve(n);
cout<<x;
}
I'm trying to write a recursive function that checks if two arrays have the same elements even if they aren't sorted, but I I can't change the arrays and I can't copy them or use a third/fourth arrays and it has to be recursive, lastly, I can't change the signature of the function.
So now I have to get rid of overwrite(A2, len, i); because that's destroying A2, but I don't see any way to do it and still have a working function... can I have a hint on how to do it? Maybe there's a way to save the elements of A2 by swapping them and then by the end of the recursion to restore them?
In short the algorithm below does a linear search of the last element of A1 in A2, if it's found, overwrite it and continue, this is done so the algorithm won't pick the same element twice, reaching the stopping condition means all the elements are there thus it will return true, otherwise will return false.
bool foo(int A1[], int A2[], int len){//both arrays are size len
int i;
bool found = false;
if (len == 0)return true;//stopping condition for recursion
else{
for (i = 0; i < len && !found; i++)//linear search
if (A1[len - 1] == A2[i]){
overwrite(A2, len, i);//this function shifts back the whole array
found = true;
}
if (found == false) return false;
else foo(A1, A2, len - 1);
}
}
Sample i/o:
A1: 3 2 1
A2: 1 2 3
True
A1: 3 2 3
A2: 1 2 3
False
A solution could be:
find what is the maximum value M in in A1 and how many times it appears
check if it's the same for A2, including the count
find what is the maximum value M1 among all values smaller than M and how many times is present in A1
check if it's the same for A2, including the count
find what is the maximum value M2 among all values smaller than M1 and how many times is present in A1
check if it's the same for A2, including the count
repeat this way until the counter for A1 and A2 is zero or is different
in code:
bool checkSame(int *A1, int *A2, int len) {
struct Same {
static bool check(int *A1, int *A2, int len, int limit) {
int index1=-1, count1=0;
for (int i=0; i<len; i++) {
if (A1[i] <= limit) {
if (index1==-1 || A1[i] > A1[index1]) {
index1 = i;
count1 = 1;
} else if (A1[i] == A1[index1]) {
count1++;
}
}
}
int index2=-1, count2=0;
for (int i=0; i<len; i++) {
if (A2[i] <= limit) {
if (index2==-1 || A2[i] > A2[index2]) {
index2 = i;
count2 = 1;
} else if (A2[i] == A2[index2]) {
count2++;
}
}
}
if (index1 == -1 && index2 == -1) return true;
if (count1 != count2 || count1 == 0 ||
A1[index1] != A2[index2]) return false;
return check(A1, A2, len, A1[index1]-1);
}
};
return Same::check(A1, A2, len, INT_MAX);
}
This algorithm is O(n^2) in time (worst case: arrays are identical and all values unique) and requires constant space if the compiler supports tail call optimization.
The following is a chart for the time needed in ms from 0 to 3000 elements on my PC.
Note that however all this is not a decent solution for the problem but just an exercise in futility. A real solution of course would need more context as there are different criteria for optimality, but I'd probably go for a closed hash table... adding elements while processing A1 and removing elements processing A2 (the removal will fail at some point if and only if the arrays are different):
bool checkSame2(int *A1, int *A2, int len) {
std::vector<int> ht(len, -1), next(len, -1);
for (int i=0; i<len; i++) {
int k = (unsigned)A1[i]*69069 % len;
next[i] = ht[k]; ht[k] = i;
}
for (int i=0; i<len; i++) {
int k = (unsigned)A2[i]*69069 % len;
int prev=-1,p=ht[k];
while (p!=-1 && A1[p] != A2[i]) {
prev = p; p = next[p];
}
if (p == -1) return false;
if (prev == -1) ht[k] = next[p]; else next[prev] = next[p];
}
return true;
}
The execution time for this solution is the purple line touching the N axis in the previous chart (hard to tell with this scale but it's linear + noise, as expected).
Just out of curiosity I also tried what would be the solution if "optimal" means just getting something working that is not hideous:
bool checkSame3(int *A1, int *A2, int len) {
std::map<int, int> counts;
for (int i=0; i<len; i++) counts[A1[i]]++;
for (int i=0; i<len; i++) {
if (--counts[A2[i]] < 0) return false;
}
return true;
}
and this is, unsurprisingly, about 30-40 times slower than the hand-coded hash table version on my PC (but of course still much faster than the recursive version).
Here is a solution that works given all your requirements. It rearranges the arrays, and then un-rearranges them. It uses recursion, uses no additional arrays, and does not change the function signature.
bool foo(int A1[], int A2[], int len){
int i;
if (len == 0){
return true;
} else {
for (i = len - 1; i >= 0; i--){
if (A1[len - 1] == A2[i]){
A2[i] = A2[len - 1];
A2[len - 1] = A1[len - 1];
bool result = foo(A1, A2, len - 1);
A2[len - 1] = A2[i];
A2[i] = A1[len - 1];
return result;
}
}
return false;
}
}
If you are allowed to temporarily change the arrays, provided that you restore them before the last recursive call has returned, you can swap the matching element in A2 with the element at index len - 1 before the recursive call, and swap them back afterwards. Since the recursive call will only look at the index range 0 through len - 2, the matching element will not be considered.