what's wrong with my code [ Dfs , Dynamic programming ] - c++

i tried to solve this problem with dfs and dynamic programming . then
i submit my code to my school grader but the answer is wrong .
am i implement something wrong with dfs .
what's wrong with my code.
PS.sorry for my bad english
The problem :
given a random number there's 2 different way you can do with this
number
1.divide it by 3 (it has to be divisible)
2.multiply it by 2
given n number find the original order before it was swapped
----EXAMPLE1---- INPUT : 6 4 8 6 3 12 9 OUTPUT : 9 3 6 12 4 8
----EXAMPLE2---- INPUT : 4 42 28 84 126 OUTPUT : 126 42 84 28
Here's my code
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
int n ;
int input[51];
map<int,int> order ;
map<int,int> memo ;
bool valid(int a){
for(int i=0;i<n;i++){
if(input[i]==a)return 1 ;
}
return 0 ;
}
void dfs(int st){
memo[st]=1;
if(valid(st/3)){
if(memo[st/3]==0){
dfs(st/3);
order[st]+=order[st/3];
}
else order[st]+=order[st/3];
}
if(valid(st*2)){
if(memo[st*2]==0){
dfs(st*2);
order[st]+=order[st*2];
}
else order[st]+=order[st*2];
}
}
int main(){
cin >> n ;
for(int i=0;i<n;i++){
cin >> input[i];
memo[input[i]]=0;
order[input[i]]=1;
}
for(int i=0;i<n;i++){
if(memo[input[i]]==0)dfs(input[i]);
}
for(int i=n;i>=1;i--){
for(int k=0;k<n;k++){
if(order[input[k]]==i){
printf("%d ",input[k]);
break;
}
}
}
}
Information the OP should have told us in the first place:
my code gave the correct answer only 7 of 10 test case .i've already
asked my teacher he only told me to be careful with the recursion .
but i couldn't figure it out what's wrong with my recursion or
something else
An example that "fails":
Here's a failing case: Say you have the sequence 3 1 2 4. valid will
return true for 4 / 3 because it sees 1 in the sequence. –
Calculuswhiz
the better solution
#include<bits/stdc++.h>
using namespace std;
struct number{
long long int r , f3 , f2 ;
};
vector<number> ans ;
bool cmp(number a,number b){
if(a.f3!=b.f3)return a.f3>=b.f3;
if(a.f2!=b.f2)return a.f2<=b.f2;
return true ;
}
int main(){
int n ;cin>> n ;
long long int input ;
for(int i=0;i<n;i++){
cin >> input ;
long long int r = input ;
long long int f3 = 0, f2 = 0 ;
while(input%3==0){
f3++;
input/=3;
}
while(input%2==0){
f2++;
input/=2;
}
ans.push_back({r,f3,f2});
}
sort(ans.begin(),ans.end(),cmp);
for(auto i : ans){
cout << i.r << " " ;
}
}

The darkest place is under the lamp.
Look at the problem definition:
1.divide it by 3 (it has to be divisible)
Where do you test for the divisibility?
So, one error is here:
if(valid(st/3)){
This test should read:
if(st % 3 == 0 && valid(st/3)){
With this simple improvement, all three test cases pass.
A hint to improve (simplify) the solution
Numbers that are not divisible by 3 must come after those divisible.
Similarly, those not divisible by 9 must be coming after those that does.
Similarly for 27, 81,...
Now, if you divide your numbers into subsets of numbers of the form n = 3^k*m, where m % 3 != 0, then in each such a subset the only operation allowed by your algorithm is "multiply by 2". So it suffices to order them in ascending order.
The problem can be solved without dfs, nor is recurnece really necessary. Just order the numbers in a funny way: in descending order with respect to the number of times the number is divisible by 3, and then in ascending order. So, a task for you: challenge your teacher with a solution that, once the numbers are read in, does just one instruction std::sort (or qsort, as I see you write in C), then tests the validity of the solution, and prints it.
Moreover, I've just proved that if a solution exists, it is unique.

Related

I need better understanding on for loops

can someone explain me how this for loop works (Line 9 in code below), and also if you can show me a simple example with it can be very helpfull, thank you anyways!
1 #include <iostream>
2 #include <cstdlib>
3
4 using namespace std;
5 int main(){
6 int n, a , b , ma=0,mb=1000000001;
7 cin >> n ;
8 cin >> a;
9 for( n--; n ; --n ){
10 cin >> b;
11 if(abs(a-b) < abs(ma-mb))
12 ma=a , mb=b;
13 else
14 if(abs(a-b) == abs(ma-mb) && ma+mb > a+b)
15 ma=a , mb=b;
16 a = b;
17 }
18 cout << ma << " " << mb;
19 return 0;
20 }
A for loop is simply another way to write a while loop. So this:
for( n--; n ; --n ){
...
}
is the same as this:
n--;
while(n) {
...
--n;
}
Which, in this specific case, is easier to read. First it decrements n, then does the loop, decrementing n again at the end of each loop, until that decrement causes n to evaluate to false by becoming 0.
This code smells a lot. If you give to n the value 10,it gives
9 (first time into loop, exectues n--)
every other iteration it executes --n till when n!=0 (which is the condition n
A for loop works the following way:
It runs for a certain number of times. We signify this with a condition. It has a start and an increment:
for (start ; condition ; increment )
{
// loop body
}
For loops and all loops are very useful when you want to perform repetitive tasks.
Lets say that you want to make a game and this game will have 3 rounds. Each one of those rounds can be implemented as an iteration of a for loop. It will look like this:
for(int round = 0; round < 3; ++round) {
// game round logic
}
In the above loop we start at 0. Once we reach 3, we would have already executed the for-loop 3 times. After each iteration of the for loop ++round gets executed, this increments the variable round by 1. We can increment it by a different value by doing: round+=2 or round*=2 etc.

exited, segmentation fault

The input for this problem is a first number that indicates how many cases will be input to be analyzed.
Input:
3
8 12
9 27
259 111
The first number means that there will be 3 cases. The next 3 lines are the cases. The program has to output the GCD (Greatest Common Divisor) of the 3 cases.
4
9
37
The code I wrote looks like the following:
#include <iostream>
#include <vector>
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
int main() {
int N;
std::cin >> N;
int i = 0;
std::vector<int> cards;
while (i <= N) {
i++;
int F1, F2;
std::cin >> F1 >> F2;
cards[i] = gcd(F1, F2);
}
for (int j; j <= N; i++) {
i++;
std::cout << cards[i] << "\n";
}
}
It reads the first integer (number of test cases), runs the loop once (reads one test case) and stops running. The terminal outputs exited, segmentation fault. What is the problem?
In your code there are some problem, first of all you haven't setted the size of the vector, that result like it has 0 lenght.
Another error are the loops;
In fact in the firts one you add 1 to i before you do all the other operation, and in this way you'll start to insert from te second component of the vector (vector start his indexing at 0).
Also in the second loop there are some problems, for example you declare a variable j that it is totally usless becouse in the folowing operations you still use i (that is setted at the end value of the previous loop, the while one).
Try to correct this things and understand it and in this way you'll understand also the reason of your error, that is pretty common in c++.
I hope that i've helped you a bit :)

Conversion of Decimal to Binary number with all the test Cases

Here's my Implementation i take the number and put it into the stack by doing mathematical calculation ... but it's not producing correct output even my logic regarding the problem is correct ...
Please detect what is wrong in my implementation. It's competitive programming Question asked by two companies in my College . So, please help me to correct the implementation....
I only want to know what is wrong with my implementation .....
Actual Question:
Input:
The first line of input contains an integer T denoting the number of test cases. There will be a single line for each testcase which contains N.
Output:
Print all binary numbers with decimal values from 1 to N in a single line.
Constraints:
1 ≤ T ≤ 106
1 ≤ N ≤ 106
Example:
Input:
2
2
5
Output:
1 10
1 10 11 100 101
Explanation:
Testcase 1: Binary numbers from 1 to 2 are 1 and 10.
This is the Required Output
Input:
2
2
5
Output:
1 10
1 10 11 100 101
And my output is :
For Input:
1
3
Your Output is:
Can any one here tell me the reason of incorrect output ..
#include<iostream>
#include <stack>
#include <queue>
using namespace std;
int main()
{
int T ;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
stack <int > s;
int num=i;
while(num>0)
{
s.push(num%2);
num=num/2 ;
}
for(int j=0;j<s.size();j++)
{
cout<<s.top();
s.pop();
}
cout<<" ";
}
cout<<endl;
}
return 0
This is the Required Output
Input:
2
2
5
Output:
1 10
1 10 11 100 101
And my output is :
For Input:
1
3
Your Output is:
Can any one here tell me the reason of incorrect output ..
The problem is here:
for(int j=0;j<s.size();j++)
{
cout<<s.top();
s.pop();
}
Suppose s has four elements.
On the first iteration, j is 0 and s.size() is 4.
On the second, j is 1 and s.size() is 3.
On the third, j is 2 and s.size() is 2, so the loop terminates.
That's two iterations instead of four.
Instead of counting the times you're going to pop, just pop until the stack is empty:
while (!s.empty())
{
cout << s.top();
s.pop();
}

How to find a sequence of size k(or more) of people that are friends with each other?

I am trying to solve a problem that was given at an exam in a university in my country. It gives me as input a file that contains on the first line 3 numbers:
The first one(n) represents the number of people
The second one(m) represents the number of friendships between people
The third one(k) is the size of the sequence(but the sequence doesn't have to be exactly as large as this number, it can be bigger)
...and on the second line the relations(m pairs of numbers with the form (a, b) meaning a is friend with b and b is friend with a).
The task is to find the sequence with the maximum length(which is at least k people) in which people are friends with each other as efficiently as possible. If there is no such sequence "NO" will be printed.
Their examples:
data.txt:
5 5 3
1 2 5 1 3 2 4 5 1 4
output:
1 4 5
data.txt:
5 5 4
1 2 5 1 3 2 4 5 1 4
output:
No
data.txt:
11 18 3
1 8 4 7 7 10 11 10 2 1 2 3 8 9 8 3 9 3 9 2 5 6 5 11 1 4 10 6 7 6 2 8 11 7 11 6
output.txt:
2 3 6 7 8 9 10 11
My approach
Friendships in this case can be represented with an undirected graph (for me at least this seems the most logical data structure to use) where vertices represent people and edges represent friendships. To be part of the sequence a vertex needs to have a degree greater than or equal to k - 1.
And that's where I stop. Currently all I can do is eliminate the nodes that don't have a degree of at least k - 1:
#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <algorithm>
std::ifstream f{ "data.txt" };
constexpr size_t LIMIT = 101;
// graph[i][j]: i is friend with j
// short to avoid vector<bool> specialization
std::vector<std::vector<short>> graph(LIMIT, std::vector<short>(LIMIT, 0));
std::vector<int> validNodes;
int numOfNodes, numOfRelationships, sequenceSize;
void Read()
{
f >> numOfNodes >> numOfRelationships >> sequenceSize;
int a;
int b;
for(int i = 1; i <= numOfRelationships; ++i) {
f >> a >> b;
graph[a][b] = graph[b][a] = 1;
}
}
int Degree(int node)
{
int result = 0;
for(int i = 1; i <= numOfNodes; ++i) {
if(i != node && graph[node][i] == 1) {
++result;
}
}
return result;
}
void KeepValidNodes()
{
for(int i = 1; i <= numOfNodes; ++i) {
if(Degree(i) < sequenceSize - 1) {
// Don't add the node to validNodes vector
// "Remove it from the graph" aka it's not friend with anyone
// all nodes that were friends with it now have a lower degree, remove them from the validNodes vector if that's the case
for(int j = 1; j <= numOfNodes; ++j) {
auto findPos = std::find(validNodes.begin(), validNodes.end(), j);
if(findPos != validNodes.end() && Degree(j) - 1 < sequenceSize - 1) {
*findPos = -1;
}
graph[i][j] = graph[j][i] = 0;
}
}
else {
validNodes.push_back(i);
}
}
}
void PrintSequence()
{
bool empty = true;
for(const int& node : validNodes) {
if(node != -1) {
empty = false;
std::cout << node << std::endl;
}
}
if(empty) {
std::cout << "No" << std::endl;
}
}
int main()
{
Read();
KeepValidNodes();
PrintSequence();
}
This works only for their first 2 examples. The only possible solution that I could think of is generating all possible combinations of nodes and see which one satisfies the requirements. How can I solve this problem efficiently as they say?
EDIT:
I am not necessarily looking for a fully working code but I don't even know how I could approach this problem.
Your problem is about finding a clique of size k or smaller. I don't know if there are any algorithms capable of doing that, but there are certainly algorithms able to find maximum size clique. Once you find the maximum size clique (let's call it n-clique) in your graph, finding a clique of size <= n reduces to extracting a subset of vertices from n-clique.
There is no polynomial time algorithm for the general case because this problem is NP-complete, so don't expect awesome results. This answer containts a short list of algorithms that will solve this problem quicker than brute-force algorithm. You should also take a look at Karp's paper on problem reducibility if you want to learn a little more about it (even if you don't apply this concept to that problem, it's worth reading because many solutions to NP-complete problems rely on reduction).

Iterated Difference

This is an spoj problem. It works, but It's too slow.
Here is the question:
Iterated Difference
You are given a list of N non-negative integers a(1), a(2), ... ,
a(N). You replace the given list by a new list: the k-th entry of the
new list is the absolute value of a(k) - a(k+1), wrapping around at
the end of the list (the k-th entry of the new list is the absolute
value of a(N) - a(1)). How many iterations of this replacement are
needed to arrive at a list in which every entry is the same integer?
For example, let N = 4 and start with the list (0 2 5 11). The successive iterations are:
2 3 6 11
1 3 5 9
2 2 4 8
0 2 4 6
2 2 2 6
0 0 4 4
0 4 0 4
4 4 4 4
Thus, 8 iterations are needed in this example.
Input
The input will contain data for a number of test cases. For each case,
there will be two lines of input. The first line will contain the
integer N (2 <= N <= 20), the number of entries in the list. The
second line will contain the list of integers, separated by one blank
space. End of input will be indicated by N = 0.
Output
For each case, there will be one line of output, specifying the case
number and the number of iterations, in the format shown in the sample
output. If the list does not attain the desired form after 1000
iterations, print 'not attained'.
Sample Input
4
0 2 5 11
5
0 2 5 11 3
4
300 8600 9000 4000
16
12 20 3 7 8 10 44 50 12 200 300 7 8 10 44 50
3
1 1 1
4
0 4 0 4
0
Sample Output
Case 1: 8 iterations
Case 2: not attained
Case 3: 3 iterations
Case 4: 50 iterations
Case 5: 0 iterations
Case 6: 1 iterations
I'm not sure of what to do to make it faster. I tried using arrays, but I get all sorts of problems trying to allocate the memory and set one array to another.
How can I make it faster? Here's my code:
#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <string>
using namespace std;
bool checker(vector<int>& nums2) {
int n = nums2[0];
for (int i = 1; i < nums2.size(); i++)
{
if (n != nums2[i])
return false;
}
return true;
}
vector<int> iterate(vector<int>& nums, int& iter, bool& attained) {
if (iter == 1000) {
attained = false;
return nums;
}
vector<int> nums2;
for (int i = 0; i < nums.size(); i++) {
if (i == nums.size() - 1)
nums2.push_back((int)abs((double)nums[i] - (double)nums[0]));
else
nums2.push_back((int)abs((double)nums[i] - (double)nums[i + 1]));
}
iter++;
return nums2;
}
int main()
{
int N = -1, count = 1;
while (1) {
int num = 0;
vector<int> nums;
string List = "";
stringstream ss;
cin >> N;
if (N == 0)
break;
cin.ignore();
cin.clear();
getline(cin, List);
ss << List;
while (ss >> num) {
nums.push_back(num);
}
int iterations = 0;
bool attained = true;
while (!checker(nums)) {
nums = iterate(nums, iterations, attained);
}
if (!attained)
cout << "case " << count << ": not attained";
else
cout << "case " << count << ": " << iterations << " iterations" << endl;
count++;
}
}
I fixed it. It was a problem with the while loop in the main function. The condition was:
while (!checker(nums)) { ... }
It would stay in the loop and repeatedly call the iterate function because if it is not attainable, then the checker will always be false. So changing the condition to:
while (!checker(nums) && attained) { ... }
would break the loop if it was not attainable.
Basically, it was just getting stuck on doing the same thing over and over; it wasn't actually slow.
Thanks, xan, for your answer.
If you want it to be a little faster you should work on debugging your array variation to avoid the vector allocations. If you want it to be a lot faster you need to do some analysis of the problem to find a better algorithm. For instance, if you see the same list twice you're in a loop and will exceed 1000 iterations. And the result will be the same if you rotate the list, which you can consider when checking for a repeated list.
Your implementation executes 1000 iterations in 25ms on my mainstream lapton. Fixed one, because there's a bug and case 2 will execute forever.
To do faster you can reuse the same vector and modify it in place, your iterator() function signature would look like:
void iterate(vector<int>& nums);
This version takes 7ms on my machine, because it doesn't allocate memory in loop.