您的位置:首页 > 其它

Sicily 1005. Roll Playing Games

2015-03-21 09:12 288 查看


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

先dp得出前n个骰子的和的方案数,然后深搜第n+1个骰子的情况。
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <vector>
#include <iomanip>
#include <map>
#include <stack>
#include <functional>
#include <list>
#include <cmath>
using namespace std;

#define MAX_SUM 1100

int d[25][MAX_SUM];  // d[i][j]表示当有i个骰子时和为j的方案数
int require[15][2];  // require[i][0]表示要求的第i个和,require[i][1]表示这个和的次数
int ans[15];  // 存放答案数组
int n;  // 已经有n个骰子已知
int r;  // 要求的和的个数
int f;  // 未知的骰子的面数
bool possible;  // 在深搜之前判断求出解的可能性
bool found;  // 深搜是否找到了解
int Min;  // 前n个骰子的和的最小值
int Max;  // 前n个骰子的和的最大值

void make() {
    memset(d, 0, sizeof(d));
    int m;
    cin >> m;
    for (int i = 0; i < m; i++) {
        int temp;
        cin >> temp;
        d[1][temp] += 1;  // 这里原本写的是d[1][temp] = 1,结果WA了好久,因为骰子的面有可能有相同值
    }
    for (int i = 2; i <= n; i++) {  // 利用动态规划先求出n个骰子的和的方案数情况
        cin >> m;
        for (int j = 0; j < m; j++) {
            int temp;
            cin >> temp;
            for (int k = 0; k < MAX_SUM; k++) {
                if (d[i - 1][k] != 0) {
                    d[i][k + temp] += d[i - 1][k];  // 第i个骰子和为k+temp的方案数等于第i-1个骰子和为k的方案数的总和
                }
            }
        }
    }
    cin >> f;
    cin >> r;
    for (int i = 0; i < r; i++) {
        cin >> require[i][0] >> require[i][1];
    }
    for (int i = 0; i < MAX_SUM; i++) {
        if (d
[i]) {
            Min = i;
            break;
        }
    }
    for (int i = MAX_SUM - 1; i >= 0; i--) {
        if (d
[i]) {
            Max = i;
            break;
        }
    }
    for (int i = 0; i < r; i++) {  // 如果要求的和比前n个骰子所能达到的最大和+50(第n+1个骰子的最大值)还大,则不可能
        if (require[i][1] != 0 && require[i][0] > Max + 50) {
            possible = false;
            return;
        }
    }
}

void DFS(int pos, int last) {

    if (pos == f) {
        for (int i = 0; i < r; i++) {
            if (require[i][1] != 0) return;
        }
        found = true;
        return;
    }
    // 这里深搜的剪枝非常巧妙
    for (int i = last; i <= 50; i++) {
        for (int j = 0; j < r; j++) {
            if (require[j][1] != 0 && Min + i > require[j][0]) return;  // 如果第j个要求的和还有次数(因为在此前的深搜次数会减少)并且前n个骰子的最小和+i(第n+1个骰子的可能值)大于第j个要求的和,由于此后的骰子的可能值必然大于等于i,所以不可能,则返回
        }
        ans[pos] = i;
        bool goOn = true;
        for (int j = 0; j < r; j++) {
            if (require[j][0] - i > 0) {
                require[j][1] -= d
[require[j][0] - i];
                if (require[j][1] < 0) goOn = false;  // 注意方案数是刚刚好,多一个少一个都不行
            }
        }
        if (goOn) DFS(pos + 1, i);
        if (found) return;
        for (int j = 0; j < r; j++) {  // 如果此方向深搜失败还原
            if (require[j][0] - i > 0) {
                require[j][1] += d
[require[j][0] - i];
            }
        }
    }
}

int main() {

    std::ios::sync_with_stdio(false);

    while (1) {
        cin >> n;
        if (!n) break;
        possible = true;
        found = false;
        make();
        if (possible) DFS(0, 1);
        if (possible && found) {
            cout << "Final die face values are";
            for (int i = 0; i < f; i++) {
                cout << " " << ans[i];
            }
            cout << endl;
        } else {
            cout << "Impossible" << endl;
        }
    }

    //getchar();
    //getchar();
    
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: