有多少可能的记分卡与输入记分卡是否一致?(How many possible scorecards

2019-07-30 04:59发布

我一直在努力解决在街头采访了以下问题。 计数记分卡(30分)

在比赛,N玩家互相玩一次。 每场比赛的结果无论是在球员胜率。 有没有关系。 你给包含每个球员的得分在比赛的最后一个记分卡。 一个球员的得分是游戏玩家在比赛中获得了总数。 然而,一些球员的得分可能已经从记分卡删除。 有多少可能的记分卡与输入记分卡是否一致?

输入:第一行包含案件T.牛逼的情况下遵循的数量。 每一种情况下包含在第一行,随后加入N-号码在第二行的数量N。 第i个数字表示S_I,第i个玩家的分数。 如果第i个玩家的分数已被删除,它是由-1表示。

输出:产量T线,包含了每种情况的答案。 输出每个结果模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

说明:对于第一种情况,有2个记分卡可能:0,1,2或1,0,2。 对于第二种情况下,有效的记分卡是1,1,1,0,1,2,0,2,1,1,0,2,1,2,0,2,0,1,2,1,0 。 对于第三种情况,唯一有效的记分卡是{0,1,2,3}。 对于第四种情况,没有有效的记分卡。 这是不可能为双方球员有得分1。

我试图想出通用功能的做法,但我真的想明确使用动态规划这一问题。 你怎么会想到这个问题复发的关系?

Answer 1:

这里是DP解决上述问题

    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;
}


Answer 2:

观察:

序列s [1],S [2],...,S [N]是一致的计分卡,这些属性必须持有:

  1. S [I1] + S [12] + .. + S [IK]> = K *(K - 1)/ 2,其中I1 <I2 <.. <IK(即,对于长度为k的每一个序列)
  2. S [1] + S [2] + .. + S [N] = N *(N - 1)/ 2

首先,我们需要检查没有被擦除的分数,只用1个条件。 然后把使用动态编程擦除分数。

让我们表示擦除分数B [I]中,不擦除分数[I];

总和{I = 1 ..升} A [1] + {总和I = 1 ..ķ} B [I]> =(K + L)*(K + L - 1)/ 2

总和{I = 1 ..升} A [1] + {总和I = 1 ..ķ} B [I]> = 0 + 1 + ... +(K + L - 1)

总和{I = 1 .. L}(A [1] - (K + I - 1))+ {总和I = 1 ..ķ} B [I]> = 0 + 1 + ... +(K - 1 )

因此,我们可以预先计算用于每k,总和的最小值{I = 1 .. L}(A [1] - (K + I - 1))/

动态规划:

状态:

DP [k]的[评分] [和]:我们知道前k个最小擦除分数,其值不超过$比分$,与和是他们的总和。

过渡:

  1. 跳过得分,DP [k]的[得分] [总和] + = DP [k]的[得分+ 1] [总和];

  2. 把$ I $值$得分$ DP [k]的[得分]的分数[总和] + = C [M - k]的[I] * DP [K + 1] [得分+ 1] [总和+ I *得分] ,其中擦除分数米数,C [n]的[K] =组合。

我的代码



Answer 3:

胜的总和应为(NC 2)

减去它们在输入中给出的已知值。 让剩余的总和(NC 2) - X被称为S.让-1的输入的数量是Q.

现在的问题归结为寻找Q变量范围从0到N-1的整数解(最大评分可能的)和总和的其数量为S

让DP [Q] [S]表示q变量,其和S的整体解决方案的数量

然后我们有,

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

DP [Q] [S]给出溶液

编辑:
观察:当x剩下的人,总胜的数量至少应为X *(X-1)/ 2(当他们打对方)。 因此,在任何时候当q人,s不能超过(NQ)(NQ-1)/ 2 = M

应该有一个更约束DP [Q] [秒]应等于0时s是大于M



Answer 4:

我试图解决这个任务,太,并认为它应该是这样的:

玩家(= N)的数目,未知卡的数量(计数的“-1”)和已知的卡的总和(计数所有卡除“-1”)中给出。 游戏可能总数应为1 + 2 + 3 + ... +(球员-1):第一个玩家(玩家-1)的对手,第二个玩家(玩家-2)等。

现在,您可以递归地计算可能的记分卡的总和:

初始化(球员,未知卡,知牌之和)为重点和可能的记分卡作为值之和的空HashMap。

如果所有的卡都定义,那么答案是0(如果所有卡的总和等于游戏可能的总数)或1(如果所有卡的总和不等于游戏可能的总数)。

如果不是所有的卡都定义,然后运行一个for循环和一个未知卡设置为0,1,2 ...(玩家-1),并尝试读取从HashMap中的结果。 如果不是在HashMap的调用方法本身并将结果保存在地图上。

递归代码应该是这样的:

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
      }
  }
}


Answer 5:

试试这个

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;
    }
}


文章来源: How many possible scorecards are consistent with the input scorecard?