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 }