1 /*
2 这道题目有一定的思维量,
3 说是有M,L两个总量,A[1]...A[N],
4 最后要使得 M+L>=sum(A[1]...A[N])....其中A[i]必须用其中一种装
5 之前的想法:
6 用 dp[i][j]:表示装到第i个物品,M中还有j没装,我们知道(M-j)+(L-j')=sum[i]
7 就能得出j',现在我们发现,尽可能得用M去装,找到M最多能装的物品的总量,剩下的用
8 L去装,只要L大于这个还没装的量就行了。
9 这样就是一个01背包的问题。
10 转换模型很重要
11 */
12
13 #include <iostream>
14 #include <string.h>
15 #include <stdio.h>
16
17 using namespace std;
18 bool dp[2010];//背包用了i的状态
19 int A[2010],path[2010],ans[2002];
20 int M,L,N,sum;
21 int main()
22 {
23 while(~scanf("%d%d",&M,&L)){
24 if (M==0 && L==0) break;
25 sum=0;
26 scanf("%d",&N);
27 for(int i=1;i<=N;i++) scanf("%d",&A[i]),sum+=A[i];
28
29 memset(dp,0,sizeof(dp));
30 dp[0]=true;
31 memset(path,0,sizeof(path));//path=1表示选择了M
32 if (L+M<sum) {
33 printf("Impossible to distribute\n");
34 continue;
35 }
36 for (int i=1;i<=N;i++){
37 for(int V=M;V-A[i]>=0;V--){
38 if (dp[V-A[i]]) {
39 dp[V]=true;
40 if (!path[V]) path[V]=i;//这句是关键,
41 }
42 }
43 }
44 int v;
45 for(v=M;v>=0;v--){
46 if (dp[v]) break;
47 }
48 if ((v==-1 && sum>L) || (dp[v] && sum-v>L)){
49 printf("Impossible to distribute\n");
50 continue;
51 }
52 int ansn=0;
53 while(v>0){
54 ans[ansn++]=path[v];
55 // cout<<path[A[v]]<<" ";
56 v-=A[path[v]];
57 // cout<<"v="<<v<<endl;
58 }
59 printf("%d",ansn);
60 for(int i=ansn-1;i>=0;i--) printf(" %d",ans[i]);
61 printf("\n");
62 }
63 return 0;
64 }