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
首先这道题很长,题意繁琐难懂他的大致意思就是给你N个已知各面数值骰子,以及一个不知道各面数值的骰子,求这个骰子各面的数值,使得这N+1的骰子数值特定的组合值v是特定的次数c因为有N个骰子是已知的,所以很容易就想到先用背包做出N个骰子组合出的可能性。考虑到最后一个骰子的r<=6,所以搜索是可行的,从小到大枚举最后一个骰子各面的数值,当然要加些剪枝,毕竟50^6还是会爆的。剪枝如下:
<p><span style="font-size:18px;">#include<iostream>
</span></p><p><span style="font-size:18px;">#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
int N,M,K,R;
int f[2][2201];
int c[11],v[11];
int ans[101];
int minn=0;
bool pr;
bool dfs(int n,int start)
{
for(int i=1;i<=M;i++)//剪枝1 如果当前产生的组合数大于题目要求的组合数,该情况不成立
if(c[i]<0)
return false;
if(n==R)
{
for(int i=1;i<=M;i++)
if(c[i]!=0)
return false;
printf("Final die face values are");
for(int i=0;i<R;i++)
printf(" %d",ans[i]);
printf("\n");
return true;
}
for(int i=start;i<=50;i++)
{
for(int k=1;k<=M;k++)
if(minn+i>v[k] && c[k]!=0) //强剪枝2 如果最小值+当前要取得数 大于v【k】,且c【k】还未达到所要求的次数,则该情况不可能
return false;
ans[n]=i;
for(int k=1;k<=M;k++)
{
if(v[k]-i>0)
c[k]-=f[0][v[k]-i];
}
if(dfs(n+1,i))
return true;
for(int k=1;k<=M;k++)
{
if(v[k]-i>0)
c[k]+=f[0][v[k]-i];
}
}
return false;
}
int main()
{
int x;
while(1)
{
scanf("%d",&N);
if(N==0)
return 0;
memset(f,0,sizeof(f));
f[0][0]=1;
for(int i=1;i<=N;i++)
{
scanf("%d",&M);
memset(f[1],0,sizeof(f[1]));
for(int j=1;j<=M;j++)
{
scanf("%d",&x);
for(int k=x;k<=i*50;k++)
if(f[0][k-x]>0)
f[1][k]+=f[0][k-x];
}
for(int k=0;k<=i*50;k++)
f[0][k]=f[1][k],f[1][k]=0;
}
scanf("%d%d",&R,&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d",&v[i],&c[i]);
}
minn=0;
while(f[0][minn]==0)minn++;//minn为原先给的骰子所能组合出最小的骰子,剪枝用
if(dfs(0,1)==false)
{
printf("Impossible\n");
}
}
}</span></p>
感谢中大bbs的题解,让我过了这题http://bbs.sysu.edu.cn/bbsanc?path=boards/ACMICPC/D.1044598826.A/D.1177998462.A/D.1223917733.A/M.1223919856.A