zoj1520

 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 }
本站公眾號
   歡迎關注本站公眾號,獲取更多信息