[hihocoder-1974] 智能分包 状态压缩dp

题目链接:https://hihocoder.com/problemset/problem/1974

题目:

小Hi在一家电商公司工作,开发订单的智能分包功能。  

用户的一个订单可能包含N种不同的商品,其中第i种购买了Ai件。电商公司一共有M个仓库,用户订单中的第i种商品在第k个仓库中的库存是cnt[k][i]件。  

有的时候单一仓库的库存不能满足用户的订单需求,这时候就需要将订单分包。比如第1种商品和第2种商品从仓库1发出,第3种商品从仓库3发出……  

特别注意订单中的同一种商品只能从单一仓库发出,也就是说不应该出现类似用户买了3瓶可乐,结果2瓶从一个仓库发出,1瓶从另一个仓库发出的情况。

请你帮小Hi实现这个功能,给定用户订单和库存,计算最少从几个不同的仓库发包。如果所有仓库一起都不能满足用户订单,输出-1。

1 <= N <= 20 1 <= M <= 50

题解:状态压缩dp

二进制状态,每一位表示一种产品当前  1有了,0没有。共有(1<<N)-1 种状态

每个仓库提前处理一下变为一个状态整数have,如果c[k][i]>=a[i](能满足客户要求),则hve的第i位为1

循环状态和仓库 ,转移方程: dp[ i | a [ j ] ]=min( dp[ i | a[ j ] ] , dp[ i ]+1 )

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int const maxn=1<<21;
 4 int n,a[25],m,have[55],dp[maxn];
 5 bool vis[25];
 6 void work(){
 7     for(int i=0;i<n;i++)if(!vis[i]){
 8         printf("-1\n");return ;
 9     }
10     int zm=(1<<n)-1;
11     for(int i=1;i<=zm;i++)dp[i]=100;
12     dp[0]=0;
13     for(int i=0;i<=zm;i++)
14         for(int j=1;j<=m;j++){
15             dp[i|have[j]]=min(dp[i|have[j]],dp[i]+1);
16         }
17     printf("%d\n",dp[zm]);
18 }
19 int main(){
20     scanf("%d%d",&n,&m);
21     for(int i=0;i<n;i++)scanf("%d",&a[i]);
22     int num;
23 //    cout<<maxn<<"haha"<<endl;
24     for(int i=1;i<=m;i++){
25         have[i]=0;
26         for(int j=0;j<n;j++){
27             scanf("%d",&num);
28             if(num>=a[j])have[i]=(have[i]<<1)+1,vis[j]=true;
29             else have[i]=have[i]<<1;
30         }
31     }
32     work();
33     return 0;
34 }

 

posted @ 2019-08-02 20:50  conver^_^  阅读(137)  评论(0编辑  收藏  举报