Combine three 32-bit identifiers into one 32-bit identifier? - algorithm

Given three identifiers, combine them into a single 32-bit value.
It is known, that the first identifier may have (2^8)-1 different values. Analogically, the second (2^8)-1 and the third (2^10)-1. Therefore the total count of identifiers of all kinds will not exceed (2^32)-1.
Example solution could be to have a map:
key: 32 bits,
value: 8 (or 10) bits.
The value would begin at 0 and be incremented every time a new identifier is provided.
Can it be done better? (instead of 3 maps) Do you see a problem with this solution?
To clarify, the identifier can hold ANY values from the range <0, 2^32). The only information that is given, is that the total number of them will not exceed (2^8)-1 (or 10th).
The identifiers can have the same values (it's completely random). Consider the randomness source memory addresses given by the OS to heap-allocated memory (e.g. using a pointer as an identifier). I realize this might work differently on x64 systems, however, I hope the general's problem solution to be similiar to this specific one.
This means that a simple bit shifting is out of question.

You could try something like this:-
#include <map>
#include <iostream>
class CombinedIdentifier
{
public:
CombinedIdentifier (unsigned id1, unsigned id2, unsigned id3)
{
m_id [0] = id1;
m_id [1] = id2;
m_id [2] = id3;
}
// version to throw exception on ID not found
static CombinedIdentifier GetIdentifier (unsigned int id)
{
// search m_store for a value = id
// if found, get key and return it
// else....throw an exception->id not found
}
// version to return found/not found instead of throwing an exception
static bool GetIdentifier (unsigned int id, CombinedIdentifier &out)
{
// search m_store for a value = id
// if found, get key and save it to 'out' and return true
// else....return false
}
int operator [] (int index) { return m_id [index]; }
bool operator < (const CombinedIdentifier &rhs) const
{
return m_id [0] < rhs.m_id [0] ? true :
m_id [1] < rhs.m_id [1] ? true :
m_id [2] < rhs.m_id [2];
}
bool operator == (const CombinedIdentifier &rhs) const
{
return m_id [0] == rhs.m_id [0] &&
m_id [1] == rhs.m_id [1] &&
m_id [2] == rhs.m_id [2];
}
bool operator != (const CombinedIdentifier &rhs) const
{
return !operator == (rhs);
}
int GetID ()
{
int
id;
std::map <CombinedIdentifier, int>::iterator
item = m_store.find (*this);
if (item == m_store.end ())
{
id = m_store.size () + 1;
m_store [*this] = id;
}
else
{
id = item->second;
}
return id;
}
private:
int
m_id [3];
static std::map <CombinedIdentifier, int>
m_store;
};
std::map <CombinedIdentifier, int>
CombinedIdentifier::m_store;
int main ()
{
CombinedIdentifier
id1 (2, 4, 10),
id2 (9, 14, 1230),
id3 (4, 1, 14560),
id4 (9, 14, 1230);
std::cout << "id1 = " << id1.GetID () << std::endl;
std::cout << "id2 = " << id2.GetID () << std::endl;
std::cout << "id3 = " << id3.GetID () << std::endl;
std::cout << "id4 = " << id4.GetID () << std::endl;
}

You can get this with bit shifting and unsafe code.
There is an article on SO: What are bitwise shift (bit-shift) operators and how do they work?
Then you can use the whole 32bit range for your three values
---- 8 bits ---- | ---- 8 bits ---- | ---- 10 bits ---- | ---- unused 6 bits ----
int result = firstValue << (8 + 10 + 6);
result += secondValue << (10 + 6);
result += thirdValue << 6;

I think you could make use of a Perfect Hash Function. In particular, the link provided in that that article to Pearson Hashing seems to be appropriate. You might even be able to cut-and-paste the included C program the 2nd article except for the fact that its output is a 64-bit number not a 32-bit one. But if you modify it slightly from
for (j=0; j<8; j++) {
// standard Pearson hash (output is h)
to
for (j=0; j<4; j++) {
// standard Pearson hash (output is h)
You'll have what you need.

Related

Custom sort and key uniqueness in std::map C++

Consider the follow std::map code.
The idea is to sort keys based only a double value even though the key contains more information.
In the custom sort used for the map, there are 3 test conditions the first of which does not work as expected.
I would like to understand why before I assume the next two actually behave as I expect them too.
Test choices 2 and 3 explicit that I do not care about the content of s_Rule (some pointer containing information) for sorting purposes but how does that also break the key mechanism of map.
In fact, 2 and 3 are literally the same since if double == double and ptr == ptr than the key is obviously the same.
This may (or may not) be related to question :
How can I declare a custom sort function on std::map declaration?
in which Simon9987 asks at the end why sort has broken the std::find function
class s_Rule
{
int x;
s_Rule() : x(0) {} // irrelevant content for question
}
typedef std::pair<double, s_Rule*> ruleSavedData;
struct sortByDouble
{
bool operator()(const ruleSavedData& a, const ruleSavedData& b) const
{
return a.first < b.first; // // not ok
// return a.first < b.first || (a.first == b.first && a.second != b.second); // ok
// return a.first <= b.first; // ok
}
};
typedef std::map<ruleSavedData, std::tuple<int, int, int>, sortByDouble> t_splitRulePool;
t_splitRulePool _splitRulePool;
auto test1 = new s_Rule();
auto test2 = new s_Rule();
auto test3 = new s_Rule();
const auto pp1 = ruleSavedData(687.00, test1);
_splitRulePool[pp1] = std::tuple<int,int,int>({1, 0, 0});
for (const auto& sr : _splitRulePool)
std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;
// Output: 687 with rule: 000001F9B60509E0 and value 1
const auto pp2 = ruleSavedData(688.00, test2);
_splitRulePool[pp2] = std::tuple<int, int, int>({ 2, 0, 0 });
for (const auto& sr : _splitRulePool)
std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;
// Output:
// 687 with rule: 000001F9B60509E0 and value 1
// 688 with rule: 000001F9B60506E0 and value 2
const auto pp3 = ruleSavedData(687.00, test3);
_splitRulePool[pp3] = std::tuple<int, int, int>({ 3, 0, 0 });
for (const auto& sr : _splitRulePool)
std::cout << sr.first.first << " with rule: " << sr.first.second << " and value " << std::get<0>(sr.second) << std::endl;
// Output:
// 687 with rule: 000001F9B60509E0 and value 3 -> key of pp1 gets overwritten with sortByDouble choice 1 but not with the others
// 688 with rule: 000001F9B60506E0 and value 2
// "Expected" output:
// 687 with rule: 000001F9B60509E0 and value 1
// 687 with rule: (&pp3) and value 3 // comes after simply because first sort < key is not true
// 688 with rule: 000001F9B60506E0 and value 2
delete test1;
delete test2;
delete test3;

Why is my search function not working as expected and how do I fix it?

I am trying to make a comparison search function that can compare two strings together based on chars. For example:
Input: "ca"
Struct vector contents under last name fields(sorted vector)(index/value): 0/"cars", 1/"roads"
Result: "Name Found at index 0 - cars"
I want users to be able to use any number of chars. The program should then compare the provided search criteria to the content of the vector and return the index of any matches.
So far I have tried to implement this alogorithm without any success, here is my code so far. Also I am pretty new to C++.
// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string name) {
int loc = -1;
int counter = 0;
int index = 0;
//when loc is no longer -1, that means the person has been found
for (int i = 0; i < people.size(); i++)
for(int k = 0; k < name.length(); k++) {
std::cout << name[k-1] << std::endl;
std::cout << people[i].lastname[k-1] << std::endl;
std::cout << counter << std::endl;
std::cout << "" << std::endl;
if(name[k-1] == people[i].lastname[k-1]) {
counter++;
}
if(counter == name.length()) {
loc = i;
break;
}
}
//if (people[i].lastname.compare(name) == 0)
//loc = i;
return loc;
}
Here is what I get in my console, I am using cout to debug:
What is player 1 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
hello sunshine
What is player 2 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
good bye
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
3
Array Sorted!!!
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
4
Player 1: good bye
Player 2: hello sunshine
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;
5
Enter the name to search:
bye
b
b
0
y
y
1
e
e
2
b
s
3
y
u
4
e
n
4
Player Found: good bye
Enter the name to search:
by
y
b
0
y
s
1
Player Found: good bye
Enter the name to search:
b
The player was not found, try again.
Enter the name to search:
sun
u
b
0
n
y
1
u
s
1
Player Found: hello sunshine
Enter the name to search:
sunshine
u
b
0
n
y
1
s
e
1
h
1
i
h
1
n
i
1
e
n
1
u
s
1
n
u
2
s
n
2
h
s
2
i
h
2
n
i
2
e
n
2
The player was not found, try again.
Enter the name to search:
EDIT: As you can see from my console output the code is returning true comparisons when it shouldn't be doing so. An example is the last comparison of is (e == n). The answer should be false but it keeps returning true.
After using code suggested in the comments I still cant get my code to work as expected and get the following errors:
||=== Build file: "no target" in "no project" (compiler: unknown) ===|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'int main()':|
E:\Coding\Cplus_work\assignmentseven.cpp|68|warning: NULL used in arithmetic [-Wpointer-arith]|
E:\Coding\Cplus_work\assignmentseven.cpp|158|warning: NULL used in arithmetic [-Wpointer-arith]|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h||In instantiation of 'bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]':|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|120|required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|161|required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|3930|required from '_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]'|
E:\Coding\Cplus_work\assignmentseven.cpp|35|required from here|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h|283|error: no match for call to '(searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>) (playerdata&)'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note: candidate: 'searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note: no known conversion for argument 1 from 'playerdata' to 'std::__cxx11::string&' {aka 'std::__cxx11::basic_string<char>&'}|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'bool sortArray(const playerdata&, const playerdata&)':|
E:\Coding\Cplus_work\assignmentseven.cpp|28|warning: control reaches end of non-void function [-Wreturn-type]|
||=== Build failed: 1 error(s), 8 warning(s) (0 minute(s), 0 second(s)) ===|
Exact code I used:
// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string (&name))
{
auto it = std::find_if(people.begin(), people.end(), [&name](std::string& person){
return person.find(name) != std::string::npos;
});
if(it != people.end()) {
return std::distance(people.begin(), it);
} else {
return -1;
}
}
Probably the main problem is that you are trying to access name[k-1] and lastname[k-1], when k=0, which results in UB.
Before continuing with your work, start learning the STL algorithms. With that in mind, your task becomes trivial using only find_if and std::string::find:
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
struct playerdata
{
std::string lastname;
playerdata(std::string lastname) :
lastname(std::move(lastname))
{
}
};
int searchArray(std::vector<playerdata>& people, const std::string& name)
{
auto it = std::find_if(people.cbegin(), people.cend(), [&name](const playerdata& player){
return player.lastname.find(name) != std::string::npos;
});
if(it != people.end())
return std::distance(people.cbegin(), it);
else
return -1;
}
}
LIVE DEMO
First of all your approach to solution is correct but needs some
improvement.
I assumed that you don`t want to solve it using regular expression or a template c++ function
which would be better way
You may have a misunderstanding about break statement which affects
only the loop it is written in break
I've explained missing points and required improvements in comment
lines
Since you didn`t specify all details I had to assume them.
`
SearchArray(std::vector<playerdata>& people, const std::string& keyWord)
{
int loc = -1;
// Use a better variable name to explain its purpose instead of `i`
// so you and other people like us can understand its meaning much faster
for (int vectorIndex = 0; vectorIndex < people.size(); vectorIndex++)
{
// if length of the name is bigger than a lastname it can`t be a match so just continue
if (keyWord.length() > people[vectorIndex].lastname.length())
{
continue;
}
int counter = 0;
int charIndexKeyWord = 0;
// Use a better variable name to explain its purpose instead of `k`
for (int charIndexIarget = 0; charIndexIarget < people[vectorIndex].lastname.length(); charIndexIarget++)
{
// Your for loop starts from 0 but you're trying to use [k-1] in your code
// you shouldn't do that, because in the first iteration of the loop it will indicate -1 [k-1]
// but it starts with 0,
//std::cout << keyWord[charIndexKeyWord] << std::endl;
//std::cout << people[vectorIndex].lastname[charIndexIarget] << std::endl;
//std::cout << counter << std::endl;
//std::cout << "" << std::endl;
// This is part of your code which needs improvment
if (keyWord[charIndexKeyWord] == people[vectorIndex].lastname[charIndexIarget])
{
counter++;
charIndexKeyWord++;
}
else
{
// If you keep your code as it is, it will may also consider matches like susnhine `sun` because
// so you need to make some improvements to get rid of it.
// if you have already founded a match but next word is not a match then you need to start looking from the beginning
if (counter != 0)
{
counter = 0;
charIndexKeyWord = 0;
}
}
if (counter == keyWord.length())
{
loc = vectorIndex;
}
}
if (loc != -1)
{
break;
}
}
return loc;
}

Recursive algorithm to find all possible solutions in a nonogram row

I am trying to write a simple nonogram solver, in a kind of bruteforce way, but I am stuck on a relatively easy task. Let's say I have a row with clues [2,3] that has a length of 10
so the solutions are:
$$-$$$----
$$--$$$---
$$---$$$--
$$----$$$-
$$-----$$$
-$$----$$$
--$$---$$$
---$$--$$$
----$$-$$$
-$$---$$$-
--$$-$$$--
I want to find all the possible solutions for a row
I know that I have to consider each block separately, and each block will have an availible space of n-(sum of remaining blocks length + number of remaining blocks) but I do not know how to progress from here
Well, this question already have a good answer, so think of this one more as an advertisement of python's prowess.
def place(blocks,total):
if not blocks: return ["-"*total]
if blocks[0]>total: return []
starts = total-blocks[0] #starts = 2 means possible starting indexes are [0,1,2]
if len(blocks)==1: #this is special case
return [("-"*i+"$"*blocks[0]+"-"*(starts-i)) for i in range(starts+1)]
ans = []
for i in range(total-blocks[0]): #append current solutions
for sol in place(blocks[1:],starts-i-1): #with all possible other solutiona
ans.append("-"*i+"$"*blocks[0]+"-"+sol)
return ans
To test it:
for i in place([2,3,2],12):
print(i)
Which produces output like:
$$-$$$-$$---
$$-$$$--$$--
$$-$$$---$$-
$$-$$$----$$
$$--$$$-$$--
$$--$$$--$$-
$$--$$$---$$
$$---$$$-$$-
$$---$$$--$$
$$----$$$-$$
-$$-$$$-$$--
-$$-$$$--$$-
-$$-$$$---$$
-$$--$$$-$$-
-$$--$$$--$$
-$$---$$$-$$
--$$-$$$-$$-
--$$-$$$--$$
--$$--$$$-$$
---$$-$$$-$$
This is what i got:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef std::vector<bool> tRow;
void printRow(tRow row){
for (bool i : row){
std::cout << ((i) ? '$' : '-');
}
std::cout << std::endl;
}
int requiredCells(const std::vector<int> nums){
int sum = 0;
for (int i : nums){
sum += (i + 1); // The number + the at-least-one-cell gap at is right
}
return (sum == 0) ? 0 : sum - 1; // The right-most number don't need any gap
}
bool appendRow(tRow init, const std::vector<int> pendingNums, unsigned int rowSize, std::vector<tRow> &comb){
if (pendingNums.size() <= 0){
comb.push_back(init);
return false;
}
int cellsRequired = requiredCells(pendingNums);
if (cellsRequired > rowSize){
return false; // There are no combinations
}
tRow prefix;
int gapSize = 0;
std::vector<int> pNumsAux = pendingNums;
pNumsAux.erase(pNumsAux.begin());
unsigned int space = rowSize;
while ((gapSize + cellsRequired) <= rowSize){
space = rowSize;
space -= gapSize;
prefix.clear();
prefix = init;
for (int i = 0; i < gapSize; ++i){
prefix.push_back(false);
}
for (int i = 0; i < pendingNums[0]; ++i){
prefix.push_back(true);
space--;
}
if (space > 0){
prefix.push_back(false);
space--;
}
appendRow(prefix, pNumsAux, space, comb);
++gapSize;
}
return true;
}
std::vector<tRow> getCombinations(const std::vector<int> row, unsigned int rowSize) {
std::vector<tRow> comb;
tRow init;
appendRow(init, row, rowSize, comb);
return comb;
}
int main(){
std::vector<int> row = { 2, 3 };
auto ret = getCombinations(row, 10);
for (tRow r : ret){
while (r.size() < 10)
r.push_back(false);
printRow(r);
}
return 0;
}
And my output is:
$$-$$$----
$$--$$$---
$$---$$$--
$$----$$$--
$$-----$$$
-$$-$$$----
-$$--$$$--
-$$---$$$-
-$$----$$$-
--$$-$$$--
--$$--$$$-
--$$---$$$
---$$-$$$-
---$$--$$$
----$$-$$$
For sure, this must be absolutely improvable.
Note: i did't test it more than already written case
Hope it works for you

Why am I keep getting WA for this solution for UVa 10511

I am trying to solve this problem, I think I have come up with a correct answer, but I am keep getting WA (wrong answer) response from the judge.
http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
The problem distilled, is, given a 1 - * relationship between party and person, 1 - * relationship between person and club. Find a 1 - 1 relationship between person and club such that for all person related to a club, the number of persons belong to a any party is less than half of the number of club.
For example, let say we have
Person1 belongs to Party1 and Club1, Club2
Person2 belongs to Party2 and Club2, Club3
Person3 Belongs to Party3 and Club3, Club1
There are two assignments possible.
Person1 Club1
Person2 Club2
Person3 Club3
and
Person1 Club2
Person2 Club3
Person3 Club1
My idea is to model this problem as a maximum flow problem as follow:
For simplicity, let say there are two parties, four persons, and three clubs.
0 is the master source
1, 2 are the nodes representing the two parties
3, 4, 5, 6 are the nodes representing the four persons
7, 8, 9 are the nodes representing the three clubs.
10 is the master sink
master source connects to each party with capacity = (3 + 1)/2 - 1 = 1. That represents there can only be at most 1 person of 1 party representing in the council (or otherwise 2 will be equals to or more than half)
for each party person pair, have a link of capacity 1. That represents each person have only 1 party and used one seat in the previously allocated number.
for each person club pair, have a link of capacity 1. That represents each person can represent one club only.
Last but not least, all clubs goes to sink with capacity 1.
If the graph above has a maximum flow equals to the number of clubs - then there exist an assignment.
I can prove the design is correct as follow:
=>
If there exist a maximum flow of the size, each club node must be sending flow of value 1, implies each club node has exactly one person representing it. The representation respect the constraint of party participation as it has at most that many person in a party representing by the party node flow.
<=
If there is a representation, construct the flow as above, so that a flow exist. The flow is maximum because the maximal possible flow is constrainted by edge connecting to the sink.
So something must be wrong either with the arguments above, or with the implementation.
Without further ado, this is my source code:
#include "stdafx.h"
// http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
// #define LOG
#include "UVa10511.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name);
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name);
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name);
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst);
int UVa10511()
{
string line;
int number_of_test_cases;
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link after the number of test cases
getline(cin, line); // consume the blank link before the first test case
for (int test_case = 0; test_case < number_of_test_cases; test_case++)
{
map<string, int> person_numbers;
map<int, string> person_namings;
map<string, int> party_numbers;
map<int, string> party_namings;
map<string, int> club_numbers;
map<int, string> club_namings;
vector<pair<int, int>> party_members;
vector<pair<int, int>> person_clubs;
while(getline(cin, line) && line != "" && line != " ")
{
string person_name;
string party_name;
string club_name;
stringstream sin(line);
sin >> person_name >> party_name;
int person_id = UVa10511_assign_person_number(person_numbers, person_namings, person_name);
int party_id = UVa10511_assign_party_number(party_numbers, party_namings, party_name);
party_members.push_back(pair<int, int>(party_id, person_id));
while(sin >> club_name)
{
int club_id = UVa10511_assign_club_number(club_numbers, club_namings, club_name);
person_clubs.push_back(pair<int, int>(person_id, club_id));
}
}
int number_of_parties = party_numbers.size();
int number_of_persons = person_numbers.size();
int number_of_clubs = club_numbers.size();
int number_of_nodes =
/* master source */ 1 +
/* parties */ number_of_parties +
/* person */ number_of_persons +
/* clubs */ number_of_clubs +
/* master sink */ 1;
vector<vector<int>> capacities;
vector<vector<int>> adjacency_list;
capacities.resize(number_of_nodes);
adjacency_list.resize(number_of_nodes);
for (int src = 0; src < number_of_nodes; src++)
{
capacities[src].resize(number_of_nodes);
for (int dst = 0; dst < number_of_nodes; dst++)
{
capacities[src][dst] = 0;
}
}
int max_party_participants = (number_of_clubs - 1) / 2; // Floor intended, not equal or more than half
for (int p = 0; p < number_of_parties; p++)
{
int party_node = p + 1;
capacities[0][party_node] = max_party_participants;
adjacency_list[0].push_back(party_node);
adjacency_list[party_node].push_back(0);
}
int person_node_start = 1 + number_of_parties;
for (vector<pair<int, int>>::iterator pmi = party_members.begin(); pmi != party_members.end(); pmi++)
{
int party_id = pmi->first;
int person_id = pmi->second;
int party_node = party_id + 1;
int person_node = person_node_start + person_id;
capacities[party_node][person_node] = 1;
adjacency_list[party_node].push_back(person_node);
adjacency_list[person_node].push_back(party_node);
}
int club_node_start = 1 + number_of_parties + number_of_persons;
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
capacities[person_node][club_node] = 1;
adjacency_list[person_node].push_back(club_node);
adjacency_list[club_node].push_back(person_node);
}
for (int c = 0; c < number_of_clubs; c++)
{
int club_node = club_node_start + c;
capacities[club_node][number_of_nodes - 1] = 1;
adjacency_list[club_node].push_back(number_of_nodes - 1);
adjacency_list[number_of_nodes - 1].push_back(club_node);
}
#ifdef LOG
cout << "digraph {" << endl;
for (int src = 0; src < number_of_nodes; src++)
{
for (vector<int>::iterator di = adjacency_list[src].begin(); di != adjacency_list[src].end(); di++)
{
int dst = *di;
cout << src << "->" << dst << " [label=\"" << capacities[src][dst] << "\"];" << endl;
}
}
cout << "}" << endl;
#endif
int total_flow = UVa10511_Edmonds_Karps(capacities, adjacency_list, 0, number_of_nodes - 1);
if (test_case > 0)
{
cout << endl;
}
if (total_flow == number_of_clubs)
{
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
if (capacities[person_node][club_node] == 0)
{
cout << person_namings[person_id] << " " << club_namings[club_id] << endl;
}
}
}
else
{
cout << "Impossible." << endl;
}
}
return 0;
}
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name)
{
int party_number;
map<string, int>::iterator probe = party_numbers.find(party_name);
if (probe == party_numbers.end())
{
party_number = party_numbers.size();
party_numbers.insert(pair<string, int>(party_name, party_number));
party_namings.insert(pair<int, string>(party_number, party_name));
}
else
{
party_number = probe->second;
}
return party_number;
}
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name)
{
int person_number;
map<string, int>::iterator probe = person_numbers.find(person_name);
if (probe == person_numbers.end())
{
person_number = person_numbers.size();
person_numbers.insert(pair<string, int>(person_name, person_number));
person_namings.insert(pair<int, string>(person_number, person_name));
}
else
{
person_number = probe->second;
}
return person_number;
}
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name)
{
int club_number;
map<string, int>::iterator probe = club_numbers.find(club_name);
if (probe == club_numbers.end())
{
club_number = club_numbers.size();
club_numbers.insert(pair<string, int>(club_name, club_number));
club_namings.insert(pair<int, string>(club_number, club_name));
}
else
{
club_number = probe->second;
}
return club_number;
}
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst)
{
int total_flow = 0;
// Step 2: Edmonds Karp's
vector<int> parents; // Allow back-tracking the path found from bfs
int number_of_nodes = capacities.size();
parents.resize(number_of_nodes); // avoid reallocation
while (true)
{
// Step 2.1: Use BFS to find an augmenting flow
queue<int> bfs_queue;
for (int n = 0; n < number_of_nodes; n++)
{
parents[n] = -1; // indicating the node is not enqueued
}
parents[src] = -2; // indicating the node is enqueued but no actual parent because this is the root
bfs_queue.push(src);
while (bfs_queue.size() > 0)
{
int current = bfs_queue.front();
bfs_queue.pop();
for (vector<int>::iterator ni = adjacency_list[current].begin(); ni != adjacency_list[current].end(); ni++)
{
int neighbor = *ni;
if (parents[neighbor] == -1 && capacities[current][neighbor] > 0)
{
parents[neighbor] = current;
bfs_queue.push(neighbor);
if (neighbor == dst)
{
break;
}
}
}
if (parents[dst] != -1)
{
break;
}
}
if (parents[dst] == -1)
{
break;
}
else
{
// We have found an augmenting path, go through the path and find the max flow through this path
int cur = dst;
bool first = true;
int max_flow_through_path = 0;
while (true)
{
int src = parents[cur];
if (src != -2)
{
int dst = cur;
int available = capacities[src][dst];
#ifdef LOG
cout << src << "--" << available << "->" << dst << endl;
#endif
cur = parents[cur];
if (first)
{
max_flow_through_path = available;
first = false;
}
else
{
max_flow_through_path = min(max_flow_through_path, available);
}
}
else
{
break;
}
}
#ifdef LOG
cout << "flowing " << max_flow_through_path << endl << endl;
#endif
total_flow += max_flow_through_path;
// Flow the max flow through the augmenting path
cur = dst;
while (true)
{
int src = parents[cur];
if (src != -2)
{
capacities[src][cur] -= max_flow_through_path;
capacities[cur][src] += max_flow_through_path;
cur = parents[cur];
}
else
{
break;
}
}
}
}
return total_flow;
}
The source code is also posted in
https://github.com/cshung/Competition/blob/master/Competition/UVa10511.cpp
The same Edmonds Karps procedure is used to pass some other UVa problems, so I think it should be fine.
UVa820, UVa10480, UVa10779, UVa11506, UVa563 are all accepted with this Edmonds Karp procedure
(These code can be found in the Git repository as well)
I have even debugging the case where Edmond Karps make a wrong choice to being with a fixed it with an augmenting path for this test case
1
Person1 Party1 Club1 Club2
Person2 Party2 Club3
Person3 Party3 Club1
As my Edmond Karps used BFS in the adjacency list order, The chosen paths are
Master Source -> Party1 -> Person1 -> Club1 -> Master Sink
Master Source -> Party2 -> Person2 -> Club3 -> Master Sink
Master Source -> Party3 -> Person3 -> Club1 -> Person1 -> Club2 -> Master Sink [This used the reverse edge and proved going through reverse edge works]
Now I am really stuck, really don't know what's wrong, any help is appreciated.
Your thinking for this problem is correct, it is a typical problem that use maximum flow algorithm.
I have read your code over and over again, I can't find any mistake. Then I change the way you handle the input, then I got accept from UVA.
Just change the code
// you code
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link before the first test case
getline(cin, line); // consume the blank link before the first test case
//line 43
while(getline(cin, line) && line != "" && line != " ")
// change to
scanf("%d\n", &number_of_test_cases);
//line 43
// while(getline(cin, line) && line.length() > 0)
After change the code, I got accept from uva .
Hope get accept response from you.

All of the option to replace an unknown number of characters

I am trying to find an algorithm that for an unknown number of characters in a string, produces all of the options for replacing some characters with stars.
For example, for the string "abc", the output should be:
*bc
a*c
ab*
**c
*b*
a**
***
It is simple enough with a known number of stars, just run through all of the options with for loops, but I'm having difficulties with an all of the options.
Every star combination corresponds to binary number, so you can use simple cycle
for i = 1 to 2^n-1
where n is string length
and set stars to the positions of 1-bits of binary representations of i
for example: i=5=101b => * b *
This is basically a binary increment problem.
You can create a vector of integer variables to represent a binary array isStar and for each iteration you "add one" to the vector.
bool AddOne (int* isStar, int size) {
isStar[size - 1] += 1
for (i = size - 1; i >= 0; i++) {
if (isStar[i] > 1) {
if (i = 0) { return true; }
isStar[i] = 0;
isStar[i - 1] += 1;
}
}
return false;
}
That way you still have the original string while replacing the characters
This is a simple binary counting problem, where * corresponds to a 1 and the original letter to a 0. So you could do it with a counter, applying a bit mask to the string, but it's just as easy to do the "counting" in place.
Here's a simple implementation in C++:
(Edit: The original question seems to imply that at least one character must be replaced with a star, so the count should start at 1 instead of 0. Or, in the following, the post-test do should be replaced with a pre-test for.)
#include <iostream>
#include <string>
// A cleverer implementation would implement C++'s iterator protocol.
// But that would cloud the simple logic of the algorithm.
class StarReplacer {
public:
StarReplacer(const std::string& s): original_(s), current_(s) {}
const std::string& current() const { return current_; }
// returns true unless we're at the last possibility (all stars),
// in which case it returns false but still resets current to the
// original configuration.
bool advance() {
for (int i = current_.size()-1; i >= 0; --i) {
if (current_[i] == '*') current_[i] = original_[i];
else {
current_[i] = '*';
return true;
}
}
return false;
}
private:
std::string original_;
std::string current_;
};
int main(int argc, const char** argv) {
for (int a = 1; a < argc; ++a) {
StarReplacer r(argv[a]);
do {
std::cout << r.current() << std::endl;
} while (r.advance());
std::cout << std::endl;
}
return 0;
}

Resources