Formula to select 6 Player Team with combined lowest rank score - /w Team salary cap of 50,000 or less

hinsdale1

Board Regular
Joined
Oct 7, 2011
Messages
60
Player Salary RankPicks
Jordan Spieth126001.75
Jason Day115004.2
Justin Rose109005.25
Jim Furyk880011.45
Bubba Watson990015.2
Rickie Fowler980019.9
Dustin Johnson1070022.3
Paul Casey870023.05
Henrik Stenson960024.1
Matt Kuchar930024.4
Zach Johnson810025.2
Brendan Steele710025.25
Robert Streb790027.95
Jason Bohn690029.2
Danny Lee770031.85
Webb Simpson790032.25
Brooks Koepka970035.85
Patrick Reed810036.35
Rory Sabbatini640036.6
Hideki Matsuyama850038.5
Chad Campbell660039.55
Russell Henley750040.1
Brandt Snedeker860042.05
David Lingmerth780043.5
Jason Kokrak610044
William McGirt640051.15
Justin Thomas770051.2
Ryan Moore760052.05
Nick Watney700052.35
Stewart Cink610053.35
Bill Haas800056.3
Will Wilcox720057.05
Tony Finau730057.1
Lee Westwood700058.4
Pat Perez650061.6
David Hearn630061.7
Ryo Ishikawa580062.25
Kevin Na690064.3
Marc Leishman710064.65
Jimmy Walker760065.6
Charl Schwartzel820065.6
Charles Howell III660067
Jim Herman630068.3
Matt Jones650069
Harris English680070.6
Scott Brown650070.95
Boo Weekley630072.5
Keegan Bradley750072.5
Scott Piercy670072.6
Russell Knox640072.9
Daniel Summerhays620075.5
J.B. Holmes730076.3
Billy Horschel750077.75
Luke Donald740079.75
Vijay Singh620080.8
Phil Mickelson830081.15
George McNeill620081.45
Carl Pettersson710082.9
Jonas Blixt690084.6
Greg Owen630086.7
Davis Love III630087.5
Ryan Palmer680088.55
Shawn Stefani620088.9
Adam Scott840089.85
Kevin Kisner690090.15
Mark Wilson570091.25
Ian Poulter710091.65
Colt Knost590092.15
James Hahn590093.5
Graham DeLaet680093.8
Steven Bowditch660095.75
Johnson Wagner600095.9
Kevin Chappell670096.1
Adam Hadwin580098
Jason Dufner6700100.2
Alex Cejka5600102.9

<colgroup><col><col><col span="2"></colgroup><tbody>
</tbody>


Can excel Formula or vba script work to analyze table and place an "X" in Picks column next to the 6 Player Team which achieves the lowest possible total combined rank (adding their 6 rank scores together) WITH a Team salary Maximum of 50,000 or less?

Little out of my pay grade but would appreciate any help which points me in the right direction.

Thank you in advance to any MATH GENIUSES who are willing to assist!
 
However, after playing around it looks like Rose, Furyk, Johnson, Steele, Streb and Bohn is your best 6 man team, 124.3 rank.

Rick

Agree! Or if you can spend $50,000 exactly, Rose, Furyk, Watson, Steele, Bohn and Sabbatini are ranked 122.95.

Brute force VBA takes only a couple of minutes with COMBIN(78,6) = 219m combinations.

Code:
Sub GetBestTeam()

    Dim vData As Variant
    Dim dRank As Double, dBestRank As Double
    Dim lTeam() As Long, lBestTeam() As Long, lCombinations As Long
    Dim lNoPlayers As Long, lSalary As Long, i As Long, j As Long, k As Long
    Const NO_CHOSEN = 6
    Const SALARY_CAP = 50000
    
    ReDim lTeam(1 To NO_CHOSEN)
    ReDim lBestTeam(1 To NO_CHOSEN)
    vData = Range("A2:C" & Range("A" & Rows.Count).End(xlUp).Row).Value
    lNoPlayers = UBound(vData)
    lCombinations = WorksheetFunction.Combin(lNoPlayers, NO_CHOSEN)
    dBestRank = 10000   'arbitrary big no
    
    For i = 1 To NO_CHOSEN
        lTeam(i) = i
    Next i
    
    For i = 2 To lCombinations
        lSalary = 0
        dRank = 0
        For j = NO_CHOSEN To 1 Step -1
            lTeam(j) = lTeam(j) + 1
            If lTeam(j) <= lNoPlayers - (NO_CHOSEN - j) Then Exit For
        Next j
        For k = j + 1 To NO_CHOSEN
            lTeam(k) = lTeam(k - 1) + 1
        Next k
        For k = 1 To NO_CHOSEN
            lSalary = lSalary + vData(lTeam(k), 2)
            dRank = dRank + vData(lTeam(k), 3)
        Next k
        If lSalary <= SALARY_CAP And dRank < dBestRank Then
            lBestTeam = lTeam
            dBestRank = dRank
        End If
    Next i
    
    Range("E1").Value = "Best Team"
    Range("E2").Resize(, NO_CHOSEN).Value = lBestTeam

End Sub

I wouldn't try brute force for many more than 78 players. But it wouldn't be hard to modify the code to think a little smarter.

Once you establish "by eye" that with a team of the better players you can get a ranking around 120 with a budget of $50,000, then we can start eliminating huge numbers of combinations of the lower ranked players. For example, if we sort the players in decreasing rank order so that Cejka is player # 1 on the team and Dufner is player #2, then for this one pairing we needn't test COMBIN(74,4)= ~1 million combinations because clearly all these combinations will have a ranking> 203.1.
 
Upvote 0

Excel Facts

What is the last column in Excel?
Excel columns run from A to Z, AA to AZ, AAA to XFD. The last column is XFD.
Nice work Stephen!.. just saw this post so haven't yet examined the code to see what you did...

But wanted to throw out a few thoughts.. if you limit the possible salary totals (for 6 players) to between 49,500 (cant see ever using a total salary less than that) and 50,000 - doesnt that dramatically reduce the number of possible combos?

Also not sure if you have already accounted for this.. but if place in the sequence doesnt matter.. wouldn't that also reduce combos? For example, there should be no distinction between team with Rose, Furyk, Watson, Steele, Bohn and Sabbatini and team with Furyk, Rose, Watson, Steele, Bohn and Sabbatini, and etc.. etc.

Anyway, not sure if these thoughts are helpful.. just wanted to quickly share before start trying to understand the code.. VERY COOL.. excited to see what can be done.

Once this is working, my next hope is to then be able to assign one, two, or three specific players to the team and then determine the best options to fill out the rest of the team (lowest combined rank at maximum of $50,000 team salary)
 
Upvote 0
Well, I limited 6 team salary total to combined 49,500 to 50,000 - not sure it made a big (if any) difference - still took my PC over 5 minutes to compute.. but..

IT WORKS!! and that is very cool. Thank you so very kindly, Mr. Crump (definitely owe u a beer).

Would it be difficult to now be able to assign one or two specific players to the team and then determine the best options to fill out the rest of the team (lowest combined rank at maximum of $50,000 team salary)? Of course, any help in this regard is greatly appreciated!

(I would also like to tweak see if can reduce the possible combo's/computing time.)

Welcome all input/advise from anyone willing to offer :)
 
Upvote 0
Let's get smarter ...

If we sort the players by salary, and sum in groups of 6, we can immediately see that we can get a ranking of <160 with a salary cap of $50,000. So I have set dBestRank = 160

Then let's sort the players in descending order by rank, ie Cejka first and Spieth last, and run the revised macro below.
This way, we only actually need to test around 240,000 combinations, which takes my machine less than a second.

Would it be difficult to now be able to assign one or two specific players to the team and then determine the best options to fill out the rest of the team?

The easiest way probably is to:

- Eliminate your two players from the list
- change Const NO_CHOSEN = 4
- Change Const SALARY_CAP = 40000 (or whatever 50000 less your two players' salaries comes to)

Code:
Sub GetBestTeam()

    Dim vData As Variant
    Dim dRank As Double, dBestRank As Double
    Dim lTeam() As Long, lBestTeam() As Long
    Dim lNoPlayers As Long, lSalary As Long, i As Long, j As Long
    Dim lIndexToChange As Long
    Dim bSuccess As Boolean
    Const NO_CHOSEN = 6
    Const SALARY_CAP = 50000
    
    ReDim lTeam(1 To NO_CHOSEN)
    ReDim lBestTeam(1 To NO_CHOSEN)
    vData = Range("A2:C" & Range("A" & Rows.Count).End(xlUp).Row).Value
    lNoPlayers = UBound(vData)
    dBestRank = 160   'based on quick inspection of data
    
    For i = 1 To NO_CHOSEN
        lTeam(i) = i
    Next i
    lTeam(NO_CHOSEN) = NO_CHOSEN - 1
    
    Do While lTeam(1) <= lNoPlayers - NO_CHOSEN
        lSalary = 0
        dRank = 0
        lIndexToChange = NO_CHOSEN
        
        'We can skip all combinations when salary cap or best rank (so far) is breached
        For i = 1 To NO_CHOSEN
            lSalary = lSalary + vData(lTeam(i), 2)
            dRank = dRank + vData(lTeam(i), 3)
            If lSalary > SALARY_CAP Or dRank >= dBestRank Then
                lIndexToChange = i
                Exit For
            End If
        Next i
        
        For i = lIndexToChange To 1 Step -1
            lTeam(i) = lTeam(i) + 1
            If lTeam(i) <= lNoPlayers - (NO_CHOSEN - i) Then Exit For
        Next i
        
        For j = i + 1 To NO_CHOSEN
            lTeam(j) = lTeam(j - 1) + 1
        Next j
        lSalary = 0
        dRank = 0
        For j = 1 To NO_CHOSEN
            lSalary = lSalary + vData(lTeam(j), 2)
            dRank = dRank + vData(lTeam(j), 3)
        Next j
        If lSalary <= SALARY_CAP And dRank < dBestRank Then
            lBestTeam = lTeam
            dBestRank = dRank
            bSuccess = True
        End If
        
        'Optional (and relatively slow): show combinations actually tested
        'lCount = lCount + 1
        'Range("L" & lCount).Resize(, NO_CHOSEN).Value = lTeam
    
    Loop
    
    Range("E1").Value = "Best Team"
    With Range("E2").Resize(, NO_CHOSEN)
        .ClearContents
        If bSuccess Then
            .Value = lBestTeam
        Else
            .Cells(1, 1).Value = "No teams!"
        End If
    End With
    
End Sub
 
Upvote 0
PS: The code doesn't allow for two or more combinations with the same combined rank. Not sure if that matters?
 
Upvote 0
Completely swag. Works like a charm. Can't thank you enough Stephen.. you ARE the man.

Last tweaks - 1) would there be a way to output the 2 or 3 best rosters (/w lowest combined rank scores) instead of just the best?

2) Also, sorry for being an idiot, but can't seem to tweak to output the best team vertically (in a column) instead of across a row? (I certainly can dig a little deeper - so feel free to ignore)

THANKS AGAIN!!! very impressed - and stoked to have workin :)
 
Upvote 0
Try this:

G1: NoInTeam
G2: NoOfPicks
G3: SalaryCap
G4: CutOffRank
F6: StartOutputHere

Excel 2010
ABCDEFGHI
1NoPlayerSalaryRankNo in team6
21Alex Cejka$5,600102.9No of picks4
32Jason Dufner$6,700100.2Salary cap$50,000
43Adam Hadwin$5,80098CutOffRank150
54Kevin Chappell$6,70096.1
65Johnson Wagner$6,00095.9Best Teams
76Steven Bowditch$6,60095.7558635858
87Graham DeLaet$6,80093.863646563
98James Hahn$5,90093.565656665
109Colt Knost$5,90092.1572666971
1110Ian Poulter$7,10091.6573737373
1211Mark Wilson$5,70091.2574747474
1312Kevin Kisner$6,90090.15122.95124.30126.80127.65
1413Adam Scott$8,40089.85$50,000$49,700$50,000$49,900
1514Shawn Stefani$6,20088.9

<tbody>
</tbody>
1

Workbook here: https://app.box.com/s/v2fdm8u3xsxhzf0h64bq5ttfqei7n63j

Code below:

Code:
Sub GetBestTeams()

    Dim vData As Variant
    Dim rngOutputCell As Range
    Dim dRank As Double, dBestRanks() As Double, dCutoffRank As Double
    Dim lTeam() As Long, lBestTeams() As Long, lBestSalaries() As Long
    Dim lNoPlayers As Long, lSalary As Long, i As Long, j As Long
    Dim lPlayerToChange As Long, lNoOfPicks As Long, lWorstPick As Long, lSuccesses As Long
    Dim lNoInTeam As Long, lSalaryCap As Long, lCutOffRank As Long
    
    lNoInTeam = Range("NoInTeam").Value
    lNoOfPicks = Range("NoOfPicks").Value
    lSalaryCap = Range("SalaryCap").Value
    lCutOffRank = Range("CutOffRank").Value
    Set rngOutputCell = Range("StartOutputHere")
    
    ReDim lTeam(1 To lNoInTeam)
    ReDim dBestRanks(1 To lNoOfPicks)
    ReDim lBestSalaries(1 To lNoOfPicks)
    ReDim lBestTeams(1 To lNoInTeam, 1 To lNoOfPicks)
    vData = Range("B2:D" & Range("B" & Rows.Count).End(xlUp).Row).Value
    lNoPlayers = UBound(vData)
    
    dCutoffRank = lCutOffRank
    lWorstPick = 1
    For i = 1 To lNoOfPicks
        dBestRanks(i) = lCutOffRank
    Next i
    For i = 1 To lNoInTeam
        lTeam(i) = i
    Next i
    lTeam(lNoInTeam) = lNoInTeam - 1
    
    'Loop through all possible combinations
    Do While lTeam(1) <= lNoPlayers - lNoInTeam
        lSalary = 0
        dRank = 0
        lPlayerToChange = lNoInTeam
        
        'If i'th player in combination causes breach of salary cap or cut-off rank, then
        'skip all sub-combinations and move to next player in i'th spot
        For i = 1 To lNoInTeam
            lSalary = lSalary + vData(lTeam(i), 2)
            dRank = dRank + vData(lTeam(i), 3)
            If lSalary > lSalaryCap Or dRank >= dCutoffRank Then
                lPlayerToChange = i
                Exit For
            End If
        Next i
        
        For i = lPlayerToChange To 1 Step -1
            lTeam(i) = lTeam(i) + 1
            If lTeam(i) <= lNoPlayers - (lNoInTeam - i) Then Exit For
        Next i
        
        For j = i + 1 To lNoInTeam
            lTeam(j) = lTeam(j - 1) + 1
        Next j
        
        'Test this combination
        lSalary = 0
        dRank = 0
        For i = 1 To lNoInTeam
            lSalary = lSalary + vData(lTeam(i), 2)
            dRank = dRank + vData(lTeam(i), 3)
        Next i
        If lSalary <= lSalaryCap And dRank < dCutoffRank Then
            'This combination is a best pick.  Re-rank best picks
            For i = 1 To lNoInTeam
                lBestTeams(i, lWorstPick) = lTeam(i)
                dBestRanks(lWorstPick) = dRank
                lBestSalaries(lWorstPick) = lSalary
            Next i
            dCutoffRank = 0
            For i = 1 To lNoOfPicks
                If dBestRanks(i) > dCutoffRank Then
                    lWorstPick = i
                    dCutoffRank = dBestRanks(i)
                End If
            Next i
        End If
    Loop
    
    'Results
    For i = 1 To lNoOfPicks
        If dBestRanks(i) < lCutOffRank Then lSuccesses = lSuccesses + 1
    Next i
    On Error Resume Next
    Range("MyResults").ClearContents
    On Error GoTo 0
    With rngOutputCell
        .Value = "Best Teams"
        If lSuccesses = 0 Then
            .Offset(1).Value = "No teams!"
        Else
            With .Offset(1).Resize(lNoInTeam + 2, lSuccesses)
                .Name = "MyResults"
                .NumberFormat = "0"
                .Value = lBestTeams
                .Rows(lNoInTeam + 1).Value = dBestRanks
                .Rows(lNoInTeam + 1).NumberFormat = "0.00"
                .Rows(lNoInTeam + 2).Value = lBestSalaries
                .Rows(lNoInTeam + 2).NumberFormat = "$#,##0"
                .Sort Key1:=.Rows(lNoInTeam + 1), Order1:=xlAscending, Orientation:=xlLeftToRight
            End With
        End If
    End With
    
End Sub
 
Upvote 0
Sorry for the delay in responding, I was completing the online form nominating Stephen Crump for the NOBEL PRIZE FOR COMPLETE AWESOMENESS.

Thanks, man - you're a stud.
 
Upvote 0
Thanks for the feedback ...

... but I'm happy to settle for the beer promised in Post #13.
(y)
 
Upvote 0
Hey Stephen - how hard would it be to modify your script to select the best Football teams? :)

Would work essentially the same as golf except have added column with positions.. the script would then need to select the best team of nine players/$50,000 salary cap - but must consist of one (1) QB, two (2) RBs , three (3) WRs, one (1) TE, one (1) FLEX (either WR,RB, or TE) and one (1) DST.

Is this something that might be accomplished without major rewrite?

I have attached your worksheet with new column for positions if helpful..

https://drive.google.com/file/d/0BxrTEtFSce2pZDU0eTVSdlMyY28/view?usp=sharing
 
Upvote 0

Forum statistics

Threads
1,216,079
Messages
6,128,687
Members
449,464
Latest member
againofsoul

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top