Sicily 1005 Roll Playing Games

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB

Description

Phil Kropotnik is a game maker, and one common problem he runs into is determining the set of dice to use in a game. In many current games, non-traditional dice are often required, that is, dice with more or fewer sides than the traditional 6-sided cube. Typically, Phil will pick random values for all but the last die, then try to determine specific values to put on the last die so that certain sums can be rolled with certain probabilities (actually, instead of dealing with probabilities, Phil just deals with the total number of different ways a given sum can be obtained by rolling all the dice). Currently he makes this determination by hand, but needless to say he would love to see this process automated. That is your task.

For example, suppose Phil starts with a 4-sided die with face values 1, 10, 15, and 20 and he wishes to determine how to label a 5-sided die so that there are a) 3 ways to obtain a sum of 2, b) 1 way to obtain a sum of 3, c) 3 ways to obtain 11, d) 4 ways to obtain 16, and e)1 way to obtain 26. To get these results he should label the faces of his 5-sided die with the values 1, 1, 1, 2, and 6. (For instance, the sum 16 may be obtained as 10 +6 or as 15 +1, with three different "1" faces to choose from on the second die, for a total of 4 different ways.)

Input

Input will consist of multiple input sets. Each input set will start with a single line containing an integer n indicating the number of dice that are already specified. Each of the next n lines describes one of these dice. Each of these lines will start with an integer f (indicating the number of faces on the die) followed by f integers indicating the value of each face. The last line of each problem instance will have the form

r m v1 c1 v2 c2 v3 c3 ... vm cm

where r is the number of faces required on the unspecified die, m is the number of sums of interest, v1, ... ,vm are these sums, and c1, ... ,cm are the counts of the desired number of different ways in which to achieve each of the respective sums.

Input values will satisfy the following constraints: 1 <= n <= 20, 3 <= f <= 20, 1 <= m <= 10, and 4 <= r <= 6. Values on the faces of all dice, both the specified ones and the unknown die, will be integers in the range 1 ... 50, and values for the vi's and ci’s are all non-negative and are strictly less than the maximum value of a 32-bit signed integer.

The last input set is followed by a line containing a single 0; it should not be processed.

Output

For each input set, output a single line containing either the phrase "Final die face values are" followed by the r face values in non-descending order, or the phrase "Impossible" if no die can be found meeting the specifications of the problem. If there are multiple dice which will solve the problem, choose the one whose lowest face value is the smallest; if there is still a tie, choose the one whose second-lowest face value is smallest, etc.

Sample Input

1
4 1 10 15 20
5 5 2 3 3 1 11 3 16 4 26 1
1
6 1 2 3 4 5 6
6 3 7 6 2 1 13 1
4
6 1 2 3 4 5 6
4 1 2 2 3
3 3 7 9
8 1 4 5 9 23 24 30 38
4 4 48 57 51 37 56 31 63 11
0

Sample Output

Final die face values are 1 1 1 2 6
Impossible
Final die face values are 3 7 9 9

Solution

给出n个骰子,每个骰子的面数和数值都已经给出,然后需要添加一个r面的骰子,使得最后掷骰子的时候满足给定的要求:对于vi有ci种方案。求骰子面值的最小解。自己解析了一下样例之后不是很好思考。要求是针对n+1个骰子的,那个这个要求是不是可以推广到n个呢,一直往下呢?于是就有了dp的方向,把n个骰子时所有的value和对应的方案数求出来,然后进行搜索。搜索的规模是50^6,毫无疑问需要剪枝。怎么剪枝是关键,我思考了很久,n+1个骰子有一个最小值,这个最小值加上当前搜索的值大于要求,且没有达到方案的话,可以进行剪枝。然而还是超时,参考了别人的思路之后,我发现自己遗漏了两个关键的剪枝策略。1.搜索的时候,数列是升序的,也就是不存在1 2 3 1这种解,因为这个和1 1 2 3是等效的。2.若其中任意一个的方案数多于要求,也是需要剪枝的。于是乎,代码就出来了。

#include <stdio.h>
#include <string.h>

int n, r, m, v[15], c[15], res[10], min;
int dp[2][1005];

bool search(int cur, int start)
{
  for (int i = 0; i < m; ++i) if (c[i] < 0) return false;
  if (cur == r)
  {
    for (int i = 0; i < m; ++i)
      if (c[i] != 0) return false;

    return true;
  }
  for (int i = start; i <= 50; ++i)
  {
    res[cur] = i;
    for (int j = 0; j < m; ++j)
    {
      if (min + i > v[j] && c[j] != 0) return false;
      if (v[j] - i > 0) c[j] -= dp[0][v[j] - i];
    }

    if (search(cur + 1, i)) return true;
    for (int j = 0; j < m; ++j) if (v[j] - i > 0) c[j] += dp[0][v[j] - i];
  }

  return false;
}

int main()
{
  while (scanf("%d", &n) != EOF && n)
  {
    int f, vf;
    memset(dp, 0, sizeof(dp));

    for (int i = 1; i <= n; ++i)
    {
      scanf("%d", &f);

      for (int j = 0; j < f; ++j)
      {
        scanf("%d", &vf);

        if (i == 1) dp[1][vf] += 1;
        else for (int k = vf; k <= i*50; ++k)
        {
          dp[1][k] += dp[0][k-vf];
        }
      }
      memcpy(dp[0], dp[1], sizeof(int)*1005);
      memset(dp[1], 0, sizeof(int)*1005);
    }
    scanf("%d%d", &r, &m);
    for (int i = 0; i < m; ++i) scanf("%d%d", &v[i], &c[i]);
    min = 0;
    while(dp[0][min] == 0) min++;

    if (search(0, 1))
    {
      printf("Final die face values are");
      for (int i = 0; i < r; ++i) printf(" %d", res[i]);
      printf("\n");
    }
    else printf("Impossible\n");
  }

  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值