How many possible scorecards are consistent with the input scorecard?

空扰寡人 提交于 2019-12-06 07:34:09

问题


I have been trying to solve the following problem in interview street. Count Scorecards(30 points)

In a tournament, N players play against each other exactly once. Each game results in either of the player winning. There are no ties. You have given a scorecard containing the scores of each player at the end of the tournament. The score of a player is the total number of games the player won in the tournament. However, the scores of some players might have been erased from the scorecard. How many possible scorecards are consistent with the input scorecard?

Input: The first line contains the number of cases T. T cases follow. Each case contains the number N on the first line followed by N numbers on the second line. The ith number denotes s_i, the score of the ith player. If the score of the ith player has been erased, it is represented by -1.

Output: Output T lines, containing the answer for each case. Output each result modulo 1000000007.

Constraints:
1 <= T <= 20
1 <= N <= 40
-1 <= s_i < N

Sample Input:
5
3
-1 -1 2
3
-1 -1 -1
4
0 1 2 3
2 
1 1
4
-1 -1 -1 2

Sample Output:
2
7
1
0
12

Explanation: For the first case, there are 2 scorecards possible: 0,1,2 or 1,0,2. For the second case, the valid scorecards are 1,1,1, 0,1,2, 0,2,1, 1,0,2, 1,2,0, 2,0,1, 2,1,0. For the third case, the only valid scorecard is {0,1,2,3}. For the fourth case, there is no valid scorecard. It is not possible for both players to have score 1.

I have tried to come up with generic functions approach, but i am really trying to nail down this problem using Dynamic programming. How can you think of recurrence relations for this problem?.


回答1:


Here is the DP solution to the above problem

    public static int[][] table;  // stores the result of the overlapping sub problems
private static int N;

public static void main(String args[]) {
    Scanner scanner = new Scanner(System.in);
    int testCases = scanner.nextInt();
    for (int i = 0; i < testCases; i++) {
        N = scanner.nextInt();
        int[] scores = new int[N];
        for (int j = 0; j < N; j++) {
            scores[j] = scanner.nextInt();
        }
        long result = process(scores) % 1000000007L;
        System.out.println(result );

    }

}

private static long process(int[] scores) {
    int sum = 0; 
    int amongPlayers = 0; //count no of players whose score has been erased(-1)
    for (int i = 0; i < N; i++) {
        if (scores[i] != -1) {
            sum += scores[i];
        } else {
            amongPlayers++; 
        }
    }

    int noGames = (N * (N -1)) /2;  // total number of games



    if (sum < noGames) {
        int distribute = noGames - sum;  // score needed to be distributed;
        table = new int[distribute + 1 ][amongPlayers + 1];
        for (int m = 0; m <= distribute; m++) {
            for (int n = 0; n <= amongPlayers; n++) {
                table[m][n] = -1;
            }
        }
        return distribute(distribute, amongPlayers); // distrubute scores among players whose score is erased(-1)
    }
    else if(sum == noGames){
        return 1;
    }

    return 0;
}

/**
 * Dynamic programming recursive calls
 * @param distribute
 * @param amongPlayers
 * @return
 */
private static int distribute(int distribute, int amongPlayers) {
    if(distribute == 0 && amongPlayers == 0)
        return 1;

    if (amongPlayers <= 0)
        return 0;

    if(distribute == 0)
        return 1;

    int result = 0;
    if (table[distribute][amongPlayers - 1] == -1) {
        int zeroResult = distribute(distribute, amongPlayers - 1);
        table[distribute][amongPlayers - 1] = zeroResult;
    }
    result += table[distribute][amongPlayers - 1];

    for (int i = 1; i < N ; i++) { // A person could win maximum of N-1 games
        if (distribute - i >= 0) {
            if (table[distribute - i][amongPlayers - 1] == -1) {
                int localResult = distribute(distribute - i,
                        amongPlayers - 1);
                table[distribute - i][amongPlayers - 1] = localResult;
            }
            result += table[distribute - i][amongPlayers - 1];
        }
    }

    return result;
}



回答2:


Observations:

Sequence s[1], s[2], ..., s[n] to be consistent scorecard, these properties must hold:

  1. s[i1] + s[i2] + .. + s[ik] >= k * (k — 1) / 2, where i1 < i2 < .. < ik (i.e for every subsequences of length k)
  2. s[1] + s[2] + .. + s[n] = n * (n — 1) / 2

First of all we need to check not erased scores, just using 1 condition. Then put erased scores using dynamic programming.

Let's denote erased scores b[i], not erased scores a[i];

sum{i = 1 .. l} a[i] + sum{i = 1 .. k} b[i] >= (k + l) * (k + l - 1) / 2

sum{i = 1 .. l} a[i] + sum{i = 1 .. k} b[i] >= 0 + 1 + .. + (k + l - 1)

sum{i = 1 .. l} (a[i] - (k + i - 1)) + sum{i = 1 .. k} b[i] >= 0 + 1 + .. + (k - 1)

So we can pre calculate for every k, minimal value of sum{i = 1 .. l} (a[i] - (k + i - 1))/

Dynamic programming:

states:

dp[k][score][sum]: we know first k minimum erased scores, and their values not exceeds $score$, and sum is their sum.

transitions:

  1. Skip score, dp[k][score][sum] += dp[k][score + 1][sum];

  2. Put $i$ scores of value $score$ dp[k][score][sum] += C[m — k][i] * dp[k + i][score + 1][sum + i*score], where m number of erased scores, C[n][k] = combination.

my code




回答3:


The total sum of the wins should be (N C 2)

Subtract the known values which are given in the input. Let the remaining sum (N C 2) - x be called S. Let the number of -1's in the input be Q.

The problem now boils down to finding the number of integral solutions of Q variables ranging from 0 to N-1 (max score possible) and sum of which is S

Let DP[q][s] denote the number of integral solutions of q variables whose sum is s

Then we have,

DP[q][s] = Sum (i=0 to N-1) DP[q-1][s-i]

DP[Q][S] gives the solution

EDIT:
Observation: For x people remaining, the number of total wins should be at least x*(x-1)/2 (when they play each other). Thus, at any time for q people, s cannot exceed (N-q)(N-q-1)/2 = M

There should be one more constraint that DP[q][s] should be equal to 0 when s is greater than M




回答4:


I'm trying to solve this assignment, too, and think it should be something like this:

The number of players (=N), the number of unknown cards (count the "-1") and the sum of the known cards (count all cards except "-1") are given. The total number of games possible should be 1 +2 +3 + ... + (players-1): The first player has (players-1) opponents, the second player (players-2) etc.

Now you can recursively calculate the sum of possible score cards:

Initialize an empty hashmap with (players, unknown cards, sum of known cards) as the key and the sum of possible score cards as the value.

If all cards are defined, then the answer is either 0 (if the sum of all cards equals the total number of games possible) or 1 (if the sum of all cards does not equal the total number of games possible).

If not all cards are defined, then run a for loop and set one unknown card to 0, 1, 2 ... (players-1) and try to read the result from the hashmap. If it is not in the hashmap call the method itself and save the result in the map.

The recursion code should be something like this:

def recursion(players: Int, games: Int, unknownCards: Int, knownScore: Int): Int = {
  unknownCards match {
    case 0 if knownScore != games => 0
    case 0 if knownScore == games => 1
    case _ =>
      map.get(players, unknownCards, knownScore) getOrElse {
        var sum = 0
        for (i <- 0 until players) sum += main(players, games, unknownCards - 1, knownScore + i)
        sum %= 1000000007
        map.put((players, unknownCards, knownScore), sum)
        sum
      }
  }
}



回答5:


Try this

import java.util.Scanner;

public class Solution {

final private static int size = 780;
private static long[][] possibleSplits = new long[size][size];

static {

    for(int i=0; i < size; ++i)
        possibleSplits[i][0] = 1;

    for(int j=0; j< size; ++j)
        possibleSplits[0][j] = j+1;

    for(int i=1; i< size; ++i)
        for(int j=1; j < size; ++j)
        {
            possibleSplits[i][j] = (possibleSplits[i-1][j] + possibleSplits[i][j-1]) % 1000000007;              
        }       
}

public long possibleWays = 0;

public Solution(int n, String scores)
{   
    long totalScores = 0;
    int numOfErasedScores = 0; 

    for(String str : scores.split(" "))
    {
        int s = Integer.parseInt(str);

        if (s < 0)
            ++numOfErasedScores;
        else        
            totalScores += s;
    }

    long totalErasedScores = ncr(n,2) - totalScores;

    if(totalErasedScores == 0)
        ++possibleWays;
    else if (totalErasedScores > 0)
        partition(n-1, totalErasedScores, numOfErasedScores);
}

private void partition(int possibleMax, long total, int split)
{       
    if (split == 0)
        return;

    possibleWays = possibleSplits[(int)total-1][split-1];       

    if (total > possibleMax)
        possibleWays -= split;      
}

public static void main(String[] args)
{
    Scanner in = new Scanner(System.in);

    int numberOfTestCases = Integer.parseInt(in.nextLine().trim());

    for(int i=0; i< numberOfTestCases; ++i)
    {
        String str = in.nextLine().trim();

        int    numberOfPlayers = Integer.parseInt(str);
        String playerScores    = in.nextLine().trim();

        long result = new Solution(numberOfPlayers, playerScores).possibleWays;

        System.out.println(result % 1000000007);
    }

    in.close();
}

public static long ncr(int n, int r)
{
    long result = 1;

    for(int i= Math.max(n-r, r)+1;i<=n;++i)
        result*= i;

    result/= fact(Math.min(n-r,r));

    return result;
}

public static long fact(int n)
{
    long result = 1;

    for(int i =2; i<= n; ++i)
        result *= i;



    return result;
    }
}


来源:https://stackoverflow.com/questions/11284978/how-many-possible-scorecards-are-consistent-with-the-input-scorecard

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!