UVA

题意:给你一些邮票面值的集合,让你选择其中一个集合,使得“能用不超过n枚集合中的邮票凑成的面值集合S中从1开始的最大连续面值”(即mex(S)-1)最大。如果有多解,输出集合大小最小的一个;如果仍有多解,输出面值从大到小排序后最小的一个。

少数能用bitset优化的dp问题之一。设bs[i]为用不超过i枚邮票能凑成的面值集合,正在放进的邮票面值为j,则有状态更新公式:$bs[i+1]=bs[i]|(bs[i]<<j)$,根据这个公式进行转移即可。

保存答案可以用vector,便于长度以及字典序的比较。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=20+5,M=10+2,inf=0x3f3f3f3f;
 5 int n,m,k,ans;
 6 vector<int> v1,v2;
 7 bitset<1000+10> bs[M];
 8 
 9 bool cmp(vector<int>& v1,vector<int>& v2) {
10     if(v1.size()!=v2.size())return v1.size()<v2.size();
11     for(int i=v1.size()-1; i>=0; --i)if(v1[i]!=v2[i])return v1[i]<v2[i];
12     return 0;
13 }
14 
15 int main() {
16     while(scanf("%d%d",&n,&m)&&n) {
17         v1.clear(),v2.clear(),ans=0;
18         while(m--) {
19             for(int i=0; i<M; ++i)bs[i].reset();
20             bs[0].set(0),v2.clear();
21             scanf("%d",&k);
22             while(k--) {
23                 int x;
24                 scanf("%d",&x);
25                 for(int i=0; i<n; ++i)bs[i+1]|=bs[i]|(bs[i]<<x);
26                 v2.push_back(x);
27             }
28             for(int i=0;; ++i)if(!bs[n].test(i)) {
29                     if(i>ans||(i==ans&&cmp(v2,v1)))ans=i,v1=v2;
30                     break;
31                 }
32         }
33         printf("max coverage = %3d :",ans-1);
34         for(int i:v1)printf("%3d",i);
35         printf("
");
36     }
37     return 0;
38 }
原文地址:https://www.cnblogs.com/asdfsag/p/10390719.html