I am trying to generate all combinations of players to make up a team of basketball players.
Let's say there's 5 positions(SG, PG, SF, PF, C) and I need to fill a rooster with 9 players, 2 of each position except the Center position for which there's only 1.
Let's say I have 10 players for each position, how can I generate a list of all possible permutations.
I would like to import the names from excel in a csv file, and then output all the combinations back to excel in another csv file.
I can figure out how to do the importing and exporting csv stuff, but i am more interested in the best algorithm to do the above permutations.
If it is easier to generate permutations, that is fine as well as I can easily eliminate duplicates in excel.
Thanks!
You could use an algorithmic technique called backtracking.
Or, depending on how many players you have, you could use brute force and just loop. For example, you could use the following to select all the combinations of 2 forwards and 1 center (this is a C++ sample just shown to illustrate the technique).
#include <iostream>
#include <fstream>
#include <algorithm>
#include <numeric>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector< string > centers;
vector< string > forwards;
centers.push_back("joey");
centers.push_back("rick");
centers.push_back("sam");
forwards.push_back("steve");
forwards.push_back("joe");
forwards.push_back("harry");
forwards.push_back("william");
for(int i = 0; i < centers.size(); ++i) {
for(int j = 0; j < forwards.size(); ++j) {
for(int k = j+1; k < forwards.size(); ++k) {
printf("%s %s %s\n",centers[i].c_str(), forwards[j].c_str(), forwards[k].c_str());
}
}
}
return 0;
}
Output:
---------- Capture Output ----------
> "c:\windows\system32\cmd.exe" /c c:\temp\temp.exe
joey steve joe
joey steve harry
joey steve william
joey joe harry
joey joe william
joey harry william
rick steve joe
rick steve harry
rick steve william
rick joe harry
rick joe william
rick harry william
sam steve joe
sam steve harry
sam steve william
sam joe harry
sam joe william
sam harry william
> Terminated with exit code 0.
However, it's important to remember that if you have a lot of players, anything you do that's "brute force", which would include backtracking (backtracking is the same idea as the loops I used above, only it uses recursion) is going to grow exponentially in running time. So for example for a 5 man roster, if you have 10 centers, 20 forwards, and 18 guards, then the running time is basically:
10 * 20 * 20 * 18 * 18 = 1,296,000
(20 * 20 because we need 2 fowards, and 18 * 18 because we need 2 guards).
1,296,000 is not too bad for running time, but when you start talking about 9 man rosters, you get much higher running times, because now you're dealing with alot more combinations.
So it depends on how much data you have as to whether this is even feasible.
Related
I am trying to create the column _Type_below which return the type value for a matching name AND a matching interval. I know I can use VLOOKUP for individual names, but lets say I have thousands of names and I can specify an array for VLOOKUP for all of them. Cheers!!
Name position _Type_ Name Range_From Range_To Type
bob 0 A bob 0 30 A
bob 5 A bob 30 100 B
bob 10 A doug 0 40 C
bob 15 A doug 40 200 A
bob 20 A
bob 30 B
bob 40 B
bob 80 B
doug 0 C
doug 20 C
doug 40 A
...
If yu have the dynamic array formula you can use FILTER():
=VLOOKUP(B2,FILTER(E:G,A2=D:D),3)
If not then your data must be sorted on D then E:
=VLOOKUP(B2,INDEX(E:E,MATCH(A2,D:D,0)):INDEX(G:G,MATCH(A2,D:D,0)+COUNTIF(D:D,A2)-1),3)
This should be relatively quick, but it requires the data sorted.
You can go super old fashioned and get the row using SumProduct() and pass that into Index(). It's not going to be speedy though.
=INDEX($I$1:$I$5, SUMPRODUCT(($F$1:$F$5=A2)*($G$1:$G$5<=B2)*($H$1:$H$5>B2)*ROW($F$1:$F$5)), 1)
I am trying to solve the Chocolate Feast challenge on HackerRank:
Little Bob loves chocolate, and he goes to a store with $N in his pocket. The price of each chocolate is $C. The store offers a discount: for every M wrappers he gives to the store, he gets one chocolate for free. How many chocolates does Bob get to eat?
Input Format:
The first line contains the number of test cases, T.
T lines follow, each of which contains three integers, N, C, and M.
Output Format:
Print the total number of chocolates Bob eats.
Constraints:
1≤T≤1000
2≤N≤105
1≤C≤N
2≤M≤N
Sample input:
3
10 2 5
12 4 4
6 2 2
Sample Output:
6
3
5
Explanation
In the first case, he can buy 5 chocolates with $10 and exchange the 5 wrappers to get one more chocolate. Thus, the total number of chocolates is 6.
In the second case, he can buy 3 chocolates for $12. However, it takes 4 wrappers to get one more chocolate. He can't avail the offer and hence the total number of chocolates remains 3.
In the third case, he can buy 3 chocolates for $6. Now he can exchange 2 of the 3 wrappers and get 1 additional piece of chocolate. Now he can use his 1 unused wrapper and the 1 wrapper of the new piece of chocolate to get one more piece of chocolate. So the total is 5.
Here is my attempt at a solution in C:
#include<stdio.h>
int main(){
int t; //total test cases
scanf("%d",&t);
for(int a0 = 0; a0 < t; a0++){
int n; //money
int c; //cost of 1 chocolate
int m; //no of wrappers to buy a new chocolate
scanf("%d %d %d",&n,&c,&m);
int tc=0,nw=0,nc=0,w=0;//tc=totalChocolates nw=newWrappers nc=newChocolates w=wrappers
tc=n/c;
w=tc;
while(w>=m){
nc=(w/m);
tc+=nc;
w-=m;
nw=w%m;
w+=nw;
}
printf("%d\n",tc);
}
return 0;
}
The problem is that my program passes some test cases whereas it fails in some others, but I am not able to find where the error is.
Moreover for some other test the time taken is above 2 secs.
Test case
Input
Excepted output
Your logic here is rather muddled:
while(w>=m){
nc=(w/m);
tc+=nc;
w-=m;
nw=w%m;
w+=nw;
}
If you change it to this then it passes all the test cases:
while(w>=m){
nc=(w/m); // how many additional bars can we buy ?
tc+=nc; // accumulate total bars purchased
w-=(nc*m); // deduct no of wrappers used to purchase additional bars
w+=nc; // accumulate additional wrappers
}
This program (before editing) outputs 10 instead of 9 for this input.
1
5 1 2
Try this in the while loop:
Subtract m*nc instead of m from w
Add nc instead of nw to tc
In my script, I start with a file of campaign contributors and anyone who donates a collective $500 is eligible for a contest. Anyone who meets that criteria I add to an array with an incrementing index to adjust the size as needed. Each index is formatted as outlined below, with the X's being a phone number. In the END portion of the script, I need to sort this array by last name($2) for printing. I've done some searching but come up empty handed. I'm not asking for someone to type the script for me, merely to point me in a better direction of search or offer advice. I need help sorting the array contestants as currently it will be filled properly with the string values the way I need them for the assignment.
Where v1,2, & 3 are the campaign contributions, I am using -F'[ :]' in my command to get both spaces and colons as field separators.
Input File lab4.data
Fname Lname:Phone__Number:v1:v2:v3
Mike Harrington:(510) 548-1278:250:100:175
Christian Dobbins:(408) 538-2358:155:90:201
Susan Dalsass:(206) 654-6279:250:60:50
Archie McNichol:(206) 548-1348:250:100:175
Jody Savage:(206) 548-1278:15:188:150
Guy Quigley:(916) 343-6410:250:100:175
Dan Savage:(406) 298-7744:450:300:275
Nancy McNeil:(206) 548-1278:250:80:75
John Goldenrod:(916) 348-4278:250:100:175
Chet Main:(510) 548-5258:50:95:135
Tom Savage:(408) 926-3456:250:168:200
Elizabeth Stachelin:(916) 440-1763:175:75:300
Array to hold anyone > $500, $8 is created and holds the value $5+$6+$7:
the array is initialized and filled in for loop given below
$8 = $5+$6+$7;
contestants[len++]
Loop to check add people to contestant array.
name and number are arrays that hold their respective values for later use.
for(i=0;i<=NR;i++)if(contrib[i]>500){contestants[len++]= name[i]" "number[i] }
Formatting of indexes(desired array values for contestant[len++]):
[0] Mike Harrington (510) 548-1278
[1] Archie McNichol (206) 548-1348
[2] Guy Quigley (916) 343-6410
[3] Dan Savage (406) 298-7744
[4] John Goldenrod (916) 348-4278
[5] Tom Savage (408) 926-3456
[6] Elizabeth Stachelin (916) 440-1763
Loop to print/check that array has been correctly filled(it is)
for (i=0; i <len; i++) {print contestants[i]}
Output:
Mike Harrington (510) 548-1278
Archie McNichol (206) 548-1348
Guy Quigley (916) 343-6410
Dan Savage (406) 298-7744
John Goldenrod (916) 348-4278
Tom Savage (408) 926-3456
Elizabeth Stachelin (916) 440-1763
Desired Final Output: Ignore formatting as it correctly displays in my terminal I just hard a hard time getting it all nice in here.
***FIRST QUARTERLY REPORT***
***CAMPAIGN 2004 CONTRIBUTIONS***
Name Phone Jan | Feb | Mar | Total Donated
Mike Harrington (510)548-1278 $ 250 $ 100 $ 175 $ 525
Christian Dobbins (408)538-2358 $ 155 $ 90 $ 201 $ 446
Susan Dalsass (206)654-6279 $ 250 $ 60 $ 50 $ 360
Archie McNichol (206)548-1348 $ 250 $ 100 $ 175 $ 525
Jody Savage (206)548-1278 $ 15 $ 188 $ 150 $ 353
Guy Quigley (916)343-6410 $ 250 $ 100 $ 175 $ 525
Dan Savage (406)298-7744 $ 450 $ 300 $ 275 $ 1025
Nancy McNeil (206)548-1278 $ 250 $ 80 $ 75 $ 405
John Goldenrod (916)348-4278 $ 250 $ 100 $ 175 $ 525
Chet Main (510)548-5258 $ 50 $ 95 $ 135 $ 280
Tom Savage (408)926-3456 $ 250 $ 168 $ 200 $ 618
Elizabeth Stachelin (916)440-1763 $ 175 $ 75 $ 300 $ 550
-----------------------------------------------------------------------------
SUMMARY
-----------------------------------------------------------------------------
The campaign received a total of $6137.00 for this quarter.
The average donation for the 12 contributors was $511.42.
The highest total contribution was $1025.00 made by Dan Savage.
***Thank you Dan Savage***
The following people donated over $500 to the campaign.
They are eligible for the quarterly drawing!!
Listed are their names(sorted by last names) and phone numbers.
John Goldenrod (916) 348-4278
Mike Harrington (510) 548-1278
Archie McNichol (206) 548-1348
Guy Quigley (916) 343-6410
Dan Savage (406) 298-7744
Tom Savage (408) 926-3456
Elizabeth Stachelin (916) 440-1763
Thank you all for your continued support!!
Using gawk, this is straightforward to do with the in-built sort functions, e.g.
BEGIN {
data["Jane Doe (123) 456-7890"] = 600;
data["Fred Adams (123) 456-7891"] = 800;
data["John Smith (123) 456-7892"] = 900;
exit;
}
END {
for (i in data) {
split(i,x," ")
data1[x[2] " " x[1] " " x[3] " " x[4]] = i;
}
asorti(data1,sdata1);
for (i in sdata1) {
print data1[sdata1[i]],"\t",data[data1[sdata1[i]]];
}
}
... which produces:
Fred Adams (123) 456-7891 800
Jane Doe (123) 456-7890 600
John Smith (123) 456-7892 900
In plain awk, the same result can be achieved by writing the array indices to a file, sorting that file and then reading the file back using getline.
The way to approach this is to produce the pre-SUMMARY output as you read the data so you don't need to store all of your data in an array, just the people who contributed more than $500 and just insert them into the array in the desired order using an insertion sort algorithm.
You would do it something like this:
awk -F':' '
NR==1 {
print "header stuff"
next
}
{
tot = $3 + $4 + $5
printf "%-20s%10s $%5s $%5s $%5s $%5s\n", $1, $2, $3, $4, $5, tot
}
tot > 500 {
split($1,name,/ /)
surname = name[2]
numContribs++
# insertion sort, check the algorithm:
for (i=1; i<=numContribs; i++) {
if (surname > surnames[i]) {
for (j=numContribs; j>i; j--) {
surnames[j+1] = surnames[j]
contribs[j+1] = contribs[j]
}
surnames[i] = surname
contribs[i] = $1 " " $2
break
}
}
}
END {
print "SUMMARY and text below it and then the list of $500+ contributors:"
for (i=1; i<=numContribs; i++) {
print contribs[i]
}
}
' lab4.data
The above is not a fully functional program. It's just intended to show you the right approach per your request.
I would like to use R for basic database purpose with two data frames: the first data frame is a list of individuals with different features:
data = data.frame("individual"=c("Steve","Bob","Simon","Lisa"),
"feature1"=c(1,2,2,3),
"feature2"=c(3,4,1,NA))
the second data frame has features descritions:
description = data.frame("feature"=c(1,2,3,4,NA),
"label"=c("foot","golf","curling","ski","No answer"))
My goal is to make a third data frame with the individuals names followed by their features descriptions:
Steve foot curling
Bob golf ski
and so on...
sqldf Try this three way join:
library(sqldf)
data[is.na(data)] <- "NA"
description[is.na(description)] <- "NA"
sqldf("select d1.individual, d2.label, d3.label
from data d1
left join description d2 on d1.feature1 = d2.feature
left join description d3 on d1.feature2 = d3.feature"
)
The output is:
individual label label
1 Simon golf foot
2 Steve foot curling
3 Bob golf ski
4 Lisa curling No answer
subscripting
This solution assumes we have run the two <- "NA" lines above.
labels <- with(description, setNames(label, feature))
with(data,
data.frame(individual, labels[feature1], labels[feature2], stringsAsFactors = FALSE)
)
which gives the output:
individual labels.feature1. labels.feature2.
3 Steve foot curling
4 Bob golf ski
1 Simon golf foot
NA Lisa curling No answer
REVISED:
Use left join.
Handle NAs as regular values.
Add second solution.
For this task, match can be used.
cbind(data[1], as.data.frame(lapply(data[-1], function(x)
description$label[match(x, description$feature)])))
individual feature1 feature2
1 Steve foot curling
2 Bob golf ski
3 Simon golf foot
4 Lisa curling No answer
Just for fun a third approach using plyr and reshape2
require(reshape2)
require(plyr)
dcast(join(melt(data, id = "individual", value.name = "feature"), description),
individual ~ variable, value.var = "label")
individual feature1 feature2
1 Bob golf ski
2 Lisa curling No answer
3 Simon golf foot
4 Steve foot curling
I have a database that i now combined using this function
def ReadAndMerge():
library1=input("Enter 1st filename to read and merge:")
with open(library1, 'r') as library1names:
library1contents = library1names.read()
library2=input("Enter 2nd filename to read and merge:")
with open(library2, 'r') as library2names:
library2contents = library2names.read()
print(library1contents)
print(library2contents)
combined_contents = library1contents + library2contents # concatenate text
print(combined_contents)
return(combined_contents)
The two databases originally looked like this
Bud Abbott 51 92.3
Mary Boyd 52 91.4
Hillary Clinton 50 82.1
and this
Don Adams 51 90.4
Jill Carney 53 76.3
Randy Newman 50 41.2
After being combined they now look like this
Bud Abbott 51 92.3
Mary Boyd 52 91.4
Hillary Clinton 50 82.1
Don Adams 51 90.4
Jill Carney 53 76.3
Randy Newman 50 41.2
if i wanted to sort this database by last names how would i go about doing that?
is there a sort function built in to python like lists? is this considered a list?
or would i have to use another function that locates the last name then orders them alphabetically
You sort with the sorted() method. But you can't sort just a big string, you need to have the data in a list or something similar. Something like this (untested):
def get_library_names(): # Better name of function
library1 = input("Enter 1st filename to read and merge:")
with open(library1, 'r') as library1names:
library1contents = library1names.readlines()
library2=input("Enter 2nd filename to read and merge:")
with open(library2, 'r') as library2names:
library2contents = library2names.readlines()
print(library1contents)
print(library2contents)
combined_contents = sorted(library1contents + library2contents)
print(combined_contents)
return(combined_contents)