WA in IITKWPCO SPOJ - c

This is a question from SPOJ
Little Feluda likes to play very much. As you know he only plays with numbers. So he is given n numbers. Now tries to group the numbers into disjoint collections each containing two numbers. He can form the collection containing two numbers iff small number in the collection is exactly half of large number.
Given n numbers, Find out how many maximum number of collections he can form ?
Input
T: number of test cases. (1 <= T <= 100).
For each test case:
First line will contain n : (1 <= n <= 100)
Then next line will contain n numbers single space seperated. Range of each number will be between 1 and 10^6.
Output
For each test case, output maximum number of collections that can be formed.
Example
Input:
2
2
1 2
3
1 2 4
Output:
1
1
my code::
#include <stdio.h>
#include <math.h>
#include <string.h>
int main()
{
int t;
scanf("%d", &t);
while (t--) {
int n, i, j;
scanf("%d", &n);
long int arr[n], mini, maxi;
char str[105];
for (i = 0;i < n;i++) {
str[i] = '0';
scanf("%ld", &arr[i]);
}
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
mini = fmin(arr[i], arr[j]);
maxi = fmax(arr[i], arr[j]);
if ((maxi == 2 * mini) && (str[i] == '0' && str[j] == '0')) {
str[i] = str[j] = '1';
break;
}
}
}
long int cnt = 0;
for (i = 0;i < n;i++) {
if (str[i] == '1') {
cnt++;
}
}
printf("%ld\n", cnt / 2);
}
return 0;
}
can someone plz point out where i am going wrong or any corner test case that i am missing??

There is a flaw in your logic.
Consider the case where the input array is {2,4,1,8}
The answer for this should be 2, since the collections {1,2} and {4,8} can be formed. However, your code will output 1 for this case (it will pair 2 with 4, and be able to create only one collection).
I have solved this problem by sorting the array, then for each element, check whether two times that element exists or not. If yes, mark it as used and increment the count of collections.
(pseudo-code):
sort(array)
count = 0;
for(i=0;i<size;i++){
if(used[i]) continue; //used elements should not be re-considered
for(j=i+1;j<size;j++){
if(array[j]==2*array[i] && !used[j]){
used[j] = true;.
count++;
}
}
}
The variable count will now have the maximum possible number of collections.
Note that searching for 2*array[i] in the array can also be implemented by binary search, but that would be unnecessary since the array is really small (size <=100)
Here's my C++ code for the problem. ( I have used the c++ standard library for sorting, you may use any sorting algorithm of your choice ).
Hope this helps.
Cheers.

Check out this easy solution:
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int main()
{
int t=0;
scanf("%d",&t);
while(t>0)
{
t=t-1;
int num=0;
long long int n[10001];
int count=0;
scanf("%d",&num);
for(int k=0;k<num;k++)
scanf("%lld",&n[k]);
sort(n,n+num);
for(int i=0;i<num;i++)
{
if(n[i]==-1)continue;
for(int j=i+1;j<num;j++)
{
if(n[j]==n[i]*2 &&n[i]!=-1 &&n[j]!=-1 )
{
count=count+1;
n[i]=-1;
n[j]=-1;
break;
}
}
}
printf("%d\n",count);
}
// getchar();
return 0;
}

Related

Why %d is showing 0 in my c program output?

The program is to find the largest number amongst all the entered integers. It asks the user to enter a number 10 times or press 0 to quit, whichever is earlier. But, the output is not as expected. I will appreciate it if you can help a newbie.
#include <stdio.h>
int main()
{
int num[10];
int max, a;
for (a = 0; a < 10; a++)
{
printf("Enter the integer: ");
scanf("%d", &num[a]);
if (num[a] == 0)
break;
}
for(a = 0; a < 10; a++)
{
num[0] = max;
if(max < num[a])
{
num[a] = max;
}
}
printf("This is the largest integer: %d", max); //The output is coming wrong here.
return 0;
}
Don't use num[0], you are overwriting it with max variable which is not initialized, so it is 0.
Use max to the minimum type variable (INT_MIN with limits.h header file) or initalize it to max = num[0] after input is captured.
#include <limits.h>
int max = INT_MIN;
Also you need to change your second for loop as follows so as to update the max variable as you iterate, and not the num[] variables. Loop variable starts with 1 if you already assumed max to be first element before, else loop variable will start with 0.
for(a = 1; a < 10; a++) // a=0 if max was initialized to INT_MIN above
{
if(num[a]>max)
{
max = num[a];
}
}
You never assign the max variable.
What you want to do is to check if the value entered is greater than each one you've previously entered, so you would need to use the following condition:
if (num[a] > max)
max = num[a];
You also need to initialize max to some value (let's say, if you expect to have only positive integers, it could be 0, but have a look at Jigsaw answer for a better solution): int max = 0;.
And eventually add an if-condition that checks if max is 0, that way you know if no values have been entered:
if(max == 0)
printf("No values have been entered.");
else printf("This is the largest integer: %d", max);
Notice that you can assign the elements of num and update max in the same for loop, therefore the second for becomes completely useless and you can remove it:
#include <stdio.h>
int main()
{
int num[10];
int max = 0, a;
for (a = 0; a < 10; a++)
{
printf("Enter the integer: ");
scanf("%d", &num[a]);
if (num[a] == 0)
break;
if (num[a] > max)
max = num[a];
}
if(max == 0)
printf("No values have been entered.");
else printf("This is the largest integer: %d", max);
return 0;
}
I suggest you to turn on your compilers warning, especially -Wall and -Wextra, so you would notice problems like these:
<source>: In function 'main':
<source>:17:16: warning: 'max' may be used uninitialized [-Wmaybe-uninitialized]
17 | num[0] = max;
| ~~~~~~~^~~~~
<source>:6:9: note: 'max' was declared here
6 | int max, a;
| ^~~
For starters this for loop
for (a = 0; a < 10; a++)
{
printf("Enter the integer: ");
scanf("%d", &num[a]);
if (num[a] == 0)
break;
}
can enter less than 10 elements in the array num due to the condition
if (num[a] == 0)
break;
So the next loop has to traverse exactly a elements of the array not 10. So in the next loop you have to use another variable for the index as for example
for( int i = 0; i < a; i++)
The variable max was not initialized
int max, a;
So this for loop invokes undefined behavior where the variable max is assigned to elements of the array or where it is compared with elements of the array.
for(a = 0; a < 10; a++)
{
num[0] = max;
if(max < num[a])
{
num[a] = max;
}
}
Moreover the variable max is not changed within the for loop. So the loop in whole does not make sense.
Pay attention to that the user can enter 0 at once. So the array will not contain any valid values. In this case the array does not have a maximum value.
Your program can look for example the following way
#include <stdio.h>
int main( void )
{
enum { N = 10 };
int num[N];
int i = 0;
do
{
printf( "Enter the integer (0 - stop): " );
scanf( "%d", &num[i] );
} while ( num[i] != 0 && ++i < N );
int max_i = 0;
for ( int j = 1; j < i; j++ )
{
if ( num[max_i] < num[j] )
{
max_i = j;
}
}
if ( i == 0 )
{
puts( "You have not entered numbers unequal to zero." );
}
else
{
printf("This is the largest integer: %d", num[max_i] );
}
return 0;
}
You neither initialise nor ever write any value at all to the variable max. Using uninitialised variables is undefined behaviour.
You seem to know how to write 0 into a. But for max you seem to have it reversed. Remember that with = the value on the right of it goes into the variable on the left of it.
To fix the problem, turn any something = max; which occurs in your code into max = something;.

Pythagorean triplets program

I have written a program that should be rather simple but on execution, it is not giving the wanted results. Even when debugging the program, I guess I found the error (getting stuck in the first if condition) but I'm not able to solve it (my inexperience perhaps). Anyways, this program, which should have been frugal, took 3 days whereas I expected it to take mere hours. Please help me with guiding me where I'm going wrong and how to solve it.
Here is the code
/*WAP to read pre entered no. of ints. consider only +ve and print the pythagorean triplets in them.*/
#include <stdio.h>
int main(){
int c,p,pp,count=0,a;
printf("How many entries to accept?\n");
scanf("%d",&a);
printf("Enter the nos.\n");
for (int i = 0; i < a; i++)
{
scanf("%d",&c);
if (c<0) //skip -ve nos.
{
continue;
}
if (count==0)
{
pp=c;
count++;
}
else if (count==1)
{
p=c;
count++;
}
else if ((pp*pp)+(p*p)==(c*c)) //Tracking count not necesarry after first three
{
printf("Pythagorean triplet found\n");
printf("%d %d %d",pp,p,c);
pp=p;
p=c;
}
}
return 0;
}
The main objective is to first scan a no. to signify the inputs to be read. Then scan the inputs, separated by a space or enter, in a loop which will only accept the no. of inputs stated before. It should neglect any -ve entries. It should print out the Pythagorean triplet if it encounters one, in a consecutive manner i.e. the triplet should appear one after the other & not randomly. We have to do the task without using arrays.
sample input is (you can consider any)(all given through the terminal)
(no. of entries)
6
1 -1 3 4 -4 5
(Here it will ignore -1 & -4)
expected output will be
Pythagorean triplet found
3 4 5
I am still learning so sorry for the elaborate program.
Thank you in advance.
since I cant see the input file I dont know if the values are sorted, since we need to identify which is the hypotenuse, makes it a bit more fiddly.
Also not clear what 'skip negatives' means. Does it mean
that we might see 3 -6 4 5 and say 'yes 3,4,5' is a triple
that we might see 3 -4 5 and say yes 3 4 5
or that we might see 3 -4 5 and simply ignore the whole set
I have assumed the first one
#include <stdio.h>
int main() {
printf("How many entries to accept?\n");
int a;
if (scanf("%d", &a) != 1) {
printf("bad input\n");
return (-1);
}
printf("Enter the nos.\n");
for (int i = 0; i < a; i++)
{
int sides[3] = { 0 };
int max = 0; // longest side length -> hypot
for (int j = 0; j < 3; j++)
{
int c;
if (scanf("%d", &c) != 1) {
printf("bad input\n");
return (-1);
}
if (c < 0) //skip -ve nos.
j--; // try again
else {
if (c > max) {
max = c;
}
sides[j] = c;
}
}
int hyp = max * max; // hypotenuse squared
int adjTot = 0; // adj sides squared total
for (int j = 0; j < 3; j++)
{
if (sides[j] == max)
continue;
adjTot += sides[j] * sides[j];
}
if (adjTot == hyp)
printf("%d %d %d is py\n", sides[0], sides[1], sides[2]);
else
printf("%d %d %d isnt py\n", sides[0], sides[1], sides[2]);
}
return 0;
}
Since you say you are reading from a file it just exits if there is non numeric data

Question regarding allocating memory for array, sorting and numbers only in C programming

I have a program that I would like to dynamically allocate an array that gets filled by the user through the terminal argument line in Linux. After the user enters the numbers, the array of numbers should be sorted.
#include <stdio.h>
#include <stdlib.h>
int main(){
int i;
int array[100];
int count = 0;
while(1){
printf("please enter a number: \n");
scanf("%d", &i);
if(i == 0){
for (int k = 0; k < count -1; k++) {
if(array[k] <= array[k + 1]){
int temp = array[k];
array[k] = array[k+1];
array[k+1] = temp;
}
}
for (int j = 0; j < count; ++j)
{
printf("%d ", array[j]);
}
printf("\n");
break;
} else {
array[count] = i;
count++;
}
}
}
This only sorts the array if I type the numbers in low to high, but if I enter the numbers from high to low eg. 4, 3, 2 and then 1, it prints 2, 3, 1 and then 4, instead of the 1,2,3,4 that it does if I type it that way.
I don't want to initialize the array with 100, I just can't get it to work if I don't initialize it. I want it to be increased if necessary.
Thank you :)
Errors/Deviations from the proposed program:
As mentioned, you want to use command line arguments - You need main(argc,*argv[]) instead of main().
For dynamic allocation you need malloc/calloc but instead of that you have used static array.
Your code shows you are not clear about concept of sorting, leave the program aside and use a pen and paper first to clear that.

This is the second SPOJ Prime Generator ? Can anyone explain why it says wrong answer?

#include <stdio.h>
#include <stdlib.h>
int main(void) {
int tc=0,start=0,end=0,i=1,n=0,j=0;
char t[3],s[11],e[11];
scanf("%s",&t);
tc=atoi(t);
for(i=1;i<=tc;i++){
scanf("%s %s",&s,&e);
start=atoi(s);
end=atoi(e);
for(n = start;n <= end;n++){
if(n==1) continue;
if(n==2 || n==3) printf("%d\n",n);
if(n%2==0 || n%3==0){
continue;
}
for(j = 5; j * j < n; j+=6){
if(n % j == 0 || n % (j+2) == 0){
continue;
}
}
printf("%d\n",n);
}
if(i!=tc)
printf("\n");
}
return 0;
}
P.S. I am not good at C but I implemented same program in Python and it was exceeding time limit. I would also like to know whether this problem can be done efficiently in Python.
Few points:
1) For taking input as integer use scanf("%d",&tc) instead of
scanf("%s",&t);
tc=atoi(t);
2) Replace your inner loop with the code I pasted below. Your inner loop doesn't check for multiples of 5. Like 5,55,95...
Simple algorithm is to check whether number has any factor till sqrt(n). If yes, then it is composite number else prime.
for(n = start;n <= end;n++){
if(n==1) continue;
int flag=1;
for(j=2;j*j<=n;j++){
if(n%j==0){
flag=0; //Is a factor
break;
}
}
if(flag)
printf("%d\n",n);
}

How to show the digits which were repeated in c?

The question is that show the digits which were repeated in C.
So I wrote this:
#include<stdio.h>
#include<stdbool.h>
int main(void){
bool number[10] = { false };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] == true)
{
printf("%d ", digit);
}
number[digit] = true;
n /= 10;
}
return 0;
}
But it will show the repeated digits again and again
(ex. input: 55544 output: 455)
I revised it:
#include<stdio.h>
int main(void){
int number[10] = { 0 };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] == 1)
{
printf("%d ", digit);
number[digit] = 2;
}
else if (number[digit] == 2)
break;
else number[digit] = 1;
n /= 10;
}
return 0;
}
It works!
However, I want to know how to do if I need to use boolean (true false), or some more efficient way?
To make your first version work, you'll need to keep track of two things:
Have you already seen this digit? (To detect duplicates)
Have you already printed it out? (To only output duplicates once)
So something like:
bool seen[10] = { false };
bool output[10] = { false };
// [...]
digit = ...;
if (seen[digit]) {
if (output[digit])) {
// duplicate, but we already printed it
} else {
// need to print it and set output to true
}
} else {
// set seen to true
}
(Once you've got that working, you can simplify the ifs. Only one is needed if you combine the two tests.)
Your second version is nearly there, but too complex. All you need to do is:
Add one to the counter for that digit every time you see it
Print the number only if the counter is exactly two.
digit = ...;
counter[digit]++;
if (counter[digit] == 2) {
// this is the second time we see this digit
// so print it out
}
n = ...;
Side benefit is that you get the count for each digit at the end.
Your second version code is not correct. You should yourself figured it out where are you wrong. You can try the below code to print the repeated elements.
#include<stdio.h>
int main(void){
int number[10] = { 0 };
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
printf("Repeated digit(s): ");
while (n > 0)
{
digit = n % 10;
if (number[digit] > 0)
{
number[digit]++;;
}
else if (number[digit] ==0 )
number[digit] = 1;
n /= 10;
}
int i=0;
for(;i<10; i++){
if(number[i]>0)
printf("%d ", i);
}
return 0;
}
In case you want to print the repeated element using bool array (first version) then it will print the elements number of times elements occur-1 times and in reverse order because you are detaching the digits from the end of number , as you are seeing in your first version code output. In case you want to print only once then you have to use int array as in above code.
It is probably much easier to handle all the input as strings:
#include <stdio.h>
#include <string.h>
int main (void) {
char str[256] = { 0 }; /* string to read */
char rep[256] = { 0 }; /* string to hold repeated digits */
int ri = 0; /* repeated digit index */
char *p = str; /* pointer to use with str */
printf ("\nEnter a number: ");
scanf ("%[^\n]s", str);
while (*p) /* for every character in string */
{
if (*(p + 1) && strchr (p + 1, *p)) /* test if remaining chars match */
if (!strchr(rep, *p)) /* test if already marked as dup */
rep[ri++] = *p; /* if not add it to string */
p++; /* increment pointer to next char */
}
printf ("\n Repeated digit(s): %s\n\n", rep);
return 0;
}
Note: you can also add a further test to limit to digits only with if (*p >= '0' && *p <= '9')
output:
$./bin/dupdigits
Enter a number: 1112223334566
Repeated digit(s): 1236
Error is here
if (number[digit] == true)
should be
if (number[digit] == false)
Eclipse + CDT plugin + stepping debug - help you next time
As everyone has given the solution: You can achieve this using the counting sort see here. Time complexity of solution will be O(n) and space complexity will be O(n+k) where k is the range in number.
However you can achieve the same by taking the XOR operation of each element with other and in case you got a XOR b as zero then its means the repeated number. But, the time complexity will be: O(n^2).
#include <stdio.h>
#define SIZE 10
main()
{
int num[SIZE] = {2,1,5,4,7,1,4,2,8,0};
int i=0, j=0;
for (i=0; i< SIZE; i++ ){
for (j=i+1; j< SIZE; j++){
if((num[i]^num[j]) == 0){
printf("Repeated element: %d\n", num[i]);
break;
}
}
}
}

Resources