I've spent a few hours trying to figure out what's wrong with my program, but I can't figure it out. This is a minimum tour cost program. (TSP)
c is for city and a is for arc(cost for travel between 2 cities)
Inputs I'm using to test:
c 1
c 2
c 3
c 4
c 5
a 1 2 1400
a 1 3 1800
a 1 4 4000
a 1 5 3500
a 2 3 1200
a 2 4 3400
a 2 5 3600
a 3 4 2300
a 3 5 2700
a 4 5 2100
And here is my code. The above inputs should give 10500 minTour, but its showing 5600.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <sstream>
#include <cstdlib>
#include <string>
#include <stdint.h>
using namespace std;
static char gFirstCity = 0;
static unsigned graph[50][50] = {0};
static unsigned minTour = 0xffffffff;
void swap (char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char* cities, unsigned start, unsigned length)
{
if (start == (length-1))
{
cout << endl;
unsigned cost =0;
cost+= graph[(unsigned)gFirstCity][(unsigned)*cities];
for(unsigned i = 0; i < length-1; i++ )
{
cost+=graph[(unsigned)cities[i]][(unsigned)cities[i+1]];
for(int i = 0; i < length; i++){
cout << (int)cities[i];
}
}
cost+=graph[(unsigned)cities[length-1]][(unsigned)gFirstCity];
for(int i = 0; i < length; i++){
cout << (int)cities[i];
}
if(cost<minTour){
minTour = cost;
}
}
else
{
for (unsigned j = start; j < length; j++)
{
swap((cities + start), (cities + j));
permute(cities, start + 1, length);
swap((cities + start), (cities + j));
}
}
}
int main()
{
string cities;
string line;
char command = 0;
unsigned city = 0;
while (getline(cin, line))
{
sscanf(line.c_str(), "%c %d", &command, &city);
if (command != 'c')
break;
cities.push_back((unsigned char)city);
}
gFirstCity = cities[0];
unsigned to = 0;
unsigned from = 0;
uint32_t cost = 0;
sscanf(line.c_str(), "%c %d %d %d", &command, &to, &from, &cost);
graph[to-1][from-1]=cost;
graph[from-1][to-1]=cost;
while (getline(cin, line))
{
sscanf(line.c_str(), "%c %d %d %d", &command, &to, &from, &cost);
graph[to-1][from-1]=cost;
graph[from-1][to-1]=cost;
}
permute((char*)cities.c_str()+1, 0, cities.length()-1);
cout << minTour << endl;
return EXIT_SUCCESS;
After adding a bit of debugging output to the code, the biggest problem appears to be that your algorithm mixes array indexes and cities inconsistently.
For example, your gStartCity is used as an array index (0-based), but is actually a city number (1-based).
You use array indexes 1-5 when actually obtaining costs, but you assign the costs to array indexes 0-4.
I believe you can get the expected result by changing both sets of graph[][] assignments to:
graph[to][from]=cost;
graph[from][to]=cost;
The definition of graph[][] will allow this without overwriting something else, and you won't live long enough for this algorithm to compute the optimal path for 49 cities, so the difference won't matter (49 cities would require about 6E+62 possible paths; even if you could check a million paths per second, this would only take about 20,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000 years to compute).
Your code is very difficult to read and follow, so I'm not sure how best to fix the fundamental problem that you are off by 1 on most of your array indices, but at least this should get it running closer to the way you expect.
Related
Elements : a b c
all combinations in such a way:abcabacbcabc
Formula to get total number of combinations of unique elements without repetition = 2^n - 1 (where n is the number of unique elements)
In our case top: 2^3 - 1 = 7
Another formula to get the combinations with specific length = n!/(r! * (n - r)!) (where n= nb of unique items and r=length)
Example for our the above case with r=2 : 3!/(2! * 1!) = 3 which is ab ac bc
Is there any algorithm or function that gets all of the 7 combinations?
I searched a lot but all i can find is one that gets the combinations with specific length only.
UPDATE:
This is what I have so far but it only gets combination with specific length:
void recur(string arr[], string out, int i, int n, int k, bool &flag)
{
flag = 1;
// invalid input
if (k > n)
return;
// base case: combination size is k
if (k == 0) {
flag = 0;
cout << out << endl;
return;
}
// start from next index till last index
for (int j = i; j < n; j++)
{
recur(arr, out + " " + arr[j], j + 1, n, k - 1,flag);
}
}
The best algorithm I've ever find to resolve this problem is to use bitwise operator. You simply need to start counting in binary. 1's in binary number means that you have to show number.
e.g.
in case of string "abc"
number , binary , string
1 , 001 , c
2 , 010 , b
3 , 011 , bc
4 , 100 , a
5 , 101 , ac
6 , 110 , ab
7 , 111 , abc
This is the best solution I've ever find. you can do it simply with loop. there will not be any memory issue.
here is the code
#include <iostream>
#include <string>
#include <math.h>
#include<stdio.h>
#include <cmath>
using namespace std;
int main()
{
string s("abcd");
int condition = pow(2, s.size());
for( int i = 1 ; i < condition ; i++){
int temp = i;
for(int j = 0 ; j < s.size() ; j++){
if (temp & 1){ // this condition will always give you the most right bit of temp.
cout << s[j];
}
temp = temp >> 1; //this statement shifts temp to the right by 1 bit.
}
cout<<endl;
}
return 0;
}
Do a simple exhaustive search.
#include <iostream>
#include <string>
using namespace std;
void exhaustiveSearch(const string& s, int i, string t = "")
{
if (i == s.size())
cout << t << endl;
else
{
exhaustiveSearch(s, i + 1, t);
exhaustiveSearch(s, i + 1, t + s[i]);
}
}
int main()
{
string s("abc");
exhaustiveSearch(s, 0);
}
Complexity: O(2^n)
Here's an answer using recursion, which will take any number of elements as strings:
#include <vector>
#include <string>
#include <iostream>
void make_combos(const std::string& start,
const std::vector<std::string>& input,
std::vector<std::string>& output)
{
for(size_t i = 0; i < input.size(); ++i)
{
auto new_string = start + input[i];
output.push_back(new_string);
if (i + 1 == input.size()) break;
std::vector<std::string> new_input(input.begin() + 1 + i, input.end());
make_combos(new_string, new_input, output);
}
}
Now you can do:
int main()
{
std::string s {};
std::vector<std::string> output {};
std::vector<std::string> input {"a", "b", "c"};
make_combos(s, input, output);
for(auto i : output) std::cout << i << std::endl;
std::cout << "There are " << output.size()
<< " unique combinations for this input." << std::endl;
return 0;
}
This outputs:
a
ab
abc
ac
b
bc
c
There are 7 unique combinations for this input.
I wrote a program where program sorts people by the each person time, and if time is the same, program sorts by the name alphabetically. Everything works fine, just I am getting extra first line full of random symbols. I of course can write if function and say not to show that first line, but is it good thing to do?
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
struct people {
string full_name;
int h;
int min;
int sec;
};
bool comp(const people &p1, const people &p2) {
return (p1.min < p2.min || p1.min == p2.min && p1.sec < p2.sec ||
p1.min == p2.min && p1.sec == p2.sec && p1.full_name < p2.full_name);
}
int main() {
int time;
string fullnamechange[30];
people peo[30];
cin >> time;
for (int i = 0; i < time; i++) {
getline(cin, peo[i].full_name); // taking everything into a string
fullnamechange[i] = peo[i].full_name;
fullnamechange[i].erase(fullnamechange[i].begin(),
fullnamechange[i].end() - 8);
peo[i].h = atoi(fullnamechange[i].c_str());
fullnamechange[i].erase(fullnamechange[i].begin(),
fullnamechange[i].end() -
5); // changing time in string to int
peo[i].min = atoi(fullnamechange[i].c_str());
fullnamechange[i].erase(fullnamechange[i].begin(),
fullnamechange[i].end() - 2);
peo[i].sec = atoi(fullnamechange[i].c_str());
}
for (int i = 0; i < time; i++) { // erasing time from string
peo[i].full_name.erase(peo[i].full_name.begin() + 20,
peo[i].full_name.end());
}
sort(peo, peo + time, comp);
cout << endl;
for (int i = 0; i < time; i++) {
cout << peo[i].full_name << " " << peo[i].min << " " << peo[i].sec << endl;
}
return 0;
}
/*
input for example:
6
Petras A. Petraitis 0 20 00
Jurgis Jurgutis 0 12 59
Romas Jonas 0 15 12
Zigmas Nosis 0 23 9
Rimas Senasis 0 15 12
output I get:
em3╣Mg n Ç 0 0 //random numbers I get
Jurgis Jurgutis 12 59
Rimas Senasis 15 12
Romas Jonas 15 12
Petras A. Petraitis 20 0
Zigmas Nosis 23 9 */
I have a C++ assignment which I've been working on in the last 2 weeks. My knowledge is very limited, as I just started learning C++ and algorithms in February.
The assignment is:
N number of guests were invited to a party. We know all guests arrival and leave time. We want to know which guest met the LEAST amount of other guests. Two guests meet when guest1_arrivaltime <= guest2_leavetime and guest2_arrivaltime <= guest1_leavetime. If there are multiple guests who met the same amount of other guests, only one needs to be printed out.
Use: standard input (cin, cout) and greedy algorithm.
N (number of guests) can range from 1 to 1 000 000, the arrival and leave time values can be between 1 and 100 000
Run time limitation: 0.1 second
Memory limitation: 32 MB
I have a working code which seems to be okay to me, but when I upload it to the school's server I only get 27 marks out of 100. I need 50 marks to pass.
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
struct guestData
{
int guestIndex;
int time;
guestData(int guestIndex, int time)
{
this->guestIndex = guestIndex;
this->time = time;
}
guestData()
{
guestIndex = 0;
time = 0;
}
};
int n;
guestData * arrive;
guestData * leave;
set<int> guestsIn;
set<int> * metSet;
int minGuests;
int minIndex = 1;
bool operator<(const guestData & l, const guestData & r)
{
return l.time < r.time;
}
void read(int n)
{
arrive = new guestData[n];
leave = new guestData[n];
metSet = new set<int>[n];
minGuests = n;
for (int i = 0; i < n; ++i){
int arriveTime;
int leaveTime;
cin >> arriveTime >> leaveTime;
arrive[i] = guestData(i, arriveTime);
leave[i] = guestData(i, leaveTime);
}
}
void process()
{
sort(arrive, arrive+n);
sort(leave, leave+n);
int i = 0, j = 0;
while (i < n && j < n)
{
if (arrive[i].time <= leave[j].time)
{
int currentTime = arrive[i].time;
int in = arrive[i].guestIndex;
for (auto it = guestsIn.begin(); it != guestsIn.end(); ++it)
{
metSet[in].insert(*it);
metSet[*it].insert(in);
}
guestsIn.insert(in);
i++;
}
else
{
int currentTime = leave[j].time;
int out = leave[j].guestIndex;
guestsIn.erase(out);
j++;
}
}
}
void findMin(){
for (int i = 0; i < n; ++i)
{
if (metSet[i].size() < minGuests)
{
minGuests = metSet[i].size();
minIndex = i+1;
}
}
}
int main()
{
cin >> n;
read(n);
process();
findMin();
cout << minIndex << " " << minGuests;
return 0;
}
The problem: it works great on the example input, which is:
8
1 3
4 8
9 12
2 5
3 9
7 10
2 3
1 3
where 8 is the n (number of guests) and then 8 x the arrival(left row) and leave time(right row) for the guests.
The output for this example input is: 3 2 which is correct, because the 3rd guests met the least amount of other guests (2)
However, I get this error on my school's website when I upload my code: ERROR CODE 11 ILLEGAL MEMORY REFERENCE
You should free the memory at the end of the program. The grading system probably detects you are not doing that.
delete[] arrive;
delete[] leave;
delete[] metSet;
Simplified version of my code looks like:
int * tab = nullptr;
int index = 0;
int size = 1; // Program works unless this is init'd to something higher!
int a = 0;
while (true)
{
int input;
std::cin >> input;
if (input == 0) break;
index++;
if (index >= size) {
size = size * 2;
int * newt = new int[size];
for (int i = 0; i < a; ++i)
newt[i] = tab[i];
delete[] tab;
tab = newt;
}
tab[a] = input;
a++;
}
Whenever I try to change 'size' integer to be bigger than 1, the program crushes. Visual Studio shouts about memory accessibility problem, but still I can't figure what's exactly wrong.
I don't have to change it, but I've struggled with this code for more than hour untill I accidently changed variable to be 1 and then it worked. I'm just curious why.
If size is bigger than one, then index >= size won't be true on the first iteration, none of the code that results in tab pointing to something is executed, so the tab[a] access is broken.
Your algorithm is rather hard to follow so I'm not proposing a concrete resolution, except to suggest redesigning it.
In addition to Lightness Races in Orbit:
Here, my approach for a revised version:
#include <iomanip>
#include <iostream>
#include <sstream>
int main()
{
int *tab = nullptr;
int len = 0, size = 0;
std::stringstream in;
in << "1 2 3 4 5 6 7 8 9 10 0";
while (true)
{
int input;
//std::cin >> input;
in >> input;
if (input == 0) break;
if (len >= size) {
size = std::max(2 * size, 1);
int * newt = new int[size];
for (int i = 0; i < len; ++i) newt[i] = tab[i];
delete[] tab;
tab = newt;
}
tab[len++] = input;
}
for (int i = 0; i < len; ++i) std::cout << ' ' << tab[i];
std::cout << '\n';
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 10
Live Demo on coliru
I must admit that I still didn't get why the original version should be broken.
There is my try on coliru which seems to run fine (although I know – running fine doesn't mean there is no U.B.). Got it.
Hi, I'm having trouble trying to convert a line of numbers, e.g.: 100 101 102, to (stoul) an dynamically allocated unsigned integer; the expected is that I can access number by number as an array, in an variable length input.
#include <iostream>
#include <new>
#include <string> //Memset
int console(){
std::string console_buffer;
unsigned long int* integersConverted = NULL;
unsigned int integersNumberOf = 0;
for( ; ; ){
std::getline(std::cin, console_buffer);
integersConverted = console_defaultSyntaxProcessing(console_buffer, &integersNumberOf);
std::cout << "Found the following integers from conversion: ";
for(unsigned int debug_tmp0 = 0; debug_tmp0 < integersNumberOf; debug_tmp0++){
std::cout << integersConverted[debug_tmp0] << " ";
std::cout << std::endl;
}
delete integersConverted;
integersConverted = NULL;
}
return 0;
}
unsigned long int* console_defaultSyntaxProcessing(std::string console_buffer, unsigned int* integersNumberOfUpdate){
*integersNumberOfUpdate = 0;
unsigned int integersNumberOf = 0;
unsigned long int* integersFound = NULL;
integersFound = new unsigned long int(sizeof(unsigned long int) * 1024);
std::size_t stringPosition = 0;
for( ; stringPosition < console_buffer.length() && integersNumberOf < 1024; ){
integersFound[integersNumberOf] = std::stoul(console_buffer, &stringPosition, 10); //10 = Decimal
integersNumberOf++;
}
*integersNumberOfUpdate = integersNumberOf;
return integersFound;
}
I'm getting correct value if I input only one number, but the whole 1024 array is printed if I input two numbers or more and all positions get the first integer. I've tried to manually set the function std::string to constant, zero the console_buffer.length() so it finds '\0', etc; unfortunately not worked..
UPDATE --- 5 minutes after the topic first posting;
The problem is, as Yashas answered, at console_defaultSyntaxProcessing for loop; stoul &stringPosition returns number of characters read from, not the position of std::string.
Another problem using stoul is, if I input 100 ( 101, it doesn't work, so follows the fixed code but shall not be used.
As lamandy suggested, use std::stringstream instead.
std::size_t stringPosition = 0;
std::size_t stringPositionSum = 0;
for( ; stringPosition < console_buffer.length() && integersNumberOf < 1024; ){
try{
integersFound[integersNumberOf] = std::stoul(&console_buffer[stringPositionSum], &stringPosition, 10);
integersNumberOf++;
stringPositionSum = stringPositionSum + stringPosition;
}
catch(std::exception& exception){
break;
} //This catch will be used constantly by this buggy code.
for( ; stringPosition < console_buffer.length() && integersNumberOf < 1024; ){
integersFound[integersNumberOf] = std::stoul(console_buffer, &stringPosition, 10); //10 = Decimal
integersNumberOf++;
}
does not do what you want.
You are passing the same string to std::stoul again and again. Your std::stoul function keeps reading the first number every time. When you had just one number, the stringPosition < console_buffer.length() caused your loop to stop. When you have more than one number, stringPosition will never exceed console_buffer.length().
The second parameter of std::stoul does not take where in the string to start reading from; it gives you the number of characters processed.
For the task you are dealing with, stringstream is what you need.
#include <iostream>
#include <sstream>
#include <array>
int main ()
{
std::istringstream console_buffer("123 345 3 5 2 3 4 5 6 7 7 232 34 332 234 55");
std::array<unsigned long, 1024> integerArray;
size_t count = 0;
while(console_buffer && count < integerArray.size())
console_buffer >> integerArray[count++];
for(int i = 0; i < count; i++)
std::cout<<integerArray[i] << ' ';
return 0;
}
Consider using std::vector and std::stringstream to ease your job.
std::vector<unsigned long int> StringToIntegerVector(const std::string& input)
{
std::istringstream iss(input);
unsigned long int temp;
std::vector<unsigned long int> results;
while (iss >> temp)
results.push_back(temp);
return results;
}