题目背景
在2020年的某一天,我们的yyy2015c01买了个高端U盘。
题目描述
你找yyy2015c01借到了这个高端的U盘,拷贝一些重要资料,但是你发现这个U盘有一些问题:
1、这个U盘的传输接口很小,只能传输大小不超过L的文件
2、这个U盘容量很小,一共只能装不超过S的文件
但是你要备份的资料却有很多,你只能备份其中的一部分。
为了选择要备份哪些文件,你给所有文件设置了一个价值Vi,你希望备份的文件总价值不小于 p
但是很快你发现这是不可能的,因为yyy2015c01的传输接口太小了,你只有花钱买一个更大的接口(更大的接口意味着可以传输更大的文件,但是购买它会花费更多的钱)
注意:你的文件不能被分割(你只能把一个文件整个的传输进去,并储存在U盘中),
你放在U盘中文件的总大小不能超过U盘容量
现在问题来了:你想知道,在满足U盘中文件价值之和 不小于 p时,最小需要多大的接口
输入输出格式
输入格式:
第1行,三个正整数 n, p, S 分别表示 文件总数, 希望最小价值p,硬盘大小
接下来n行
每行两个正整数 Wi, Vi 表示 第i个文件的大小,和价值
输出格式:
一共1行,输出一个正整数表示最小需要的接口大小
如果无解输出 “No Solution!” 不含引号
输入输出样例
3 3 5 2 2 1 2 3 2
2 (买一个大小为2接口,把物品1、2放进U盘)
2 3 505 1 2 500 1
500(买一个大小为500的接口)
3 3 2 2 2 1 2 3 2
No Solution!(本来可以买大小为2的接口,可是U盘容量放不下足够的文件)
4 5 6 5 1 5 2 5 3 1 1
No Solution!
说明
数据范围:
1 ≤ n, Wi, S ≤ 1 000
1 ≤ Vi ≤ 1 000 000
1 ≤ p ≤ 1 000 000 000
数据较小,请勿乱搞。
如果数据出现疏漏,请联系出题人@a710128
向本题主人公yyy2015c01同学致敬!
挺有意思的一道题,用二分+背包,二分枚举最小的端口,dp验证价值能否大于最小价值。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 const int MAXN = 1010; 7 int f[MAXN],v[MAXN],w[MAXN]; //f[i]大小为i时价值最大,v大小,w价值 8 int n,m,s; //文件个数,最小价值,U盘容量 9 10 bool dp(int x) 11 { 12 memset(f,0,sizeof(f)); 13 for (int i=1; i<=n; ++i) 14 { 15 if (v[i]>x) continue ; 16 for (int j=s; j>=v[i]; --j) 17 f[j] = max(f[j],f[j-v[i]]+w[i]); 18 } 19 if (f[s]<m) return false ; 20 return true ; 21 } 22 int main() 23 { 24 scanf("%d%d%d",&n,&m,&s); 25 for (int i=1; i<=n; ++i) 26 { 27 scanf("%d%d",&v[i],&w[i]); 28 } 29 int l = 0 , r = s, ans = -1; 30 while (l<=r) 31 { 32 int mid = (l+r)>>1; 33 if (dp(mid)) 34 { 35 ans = mid; 36 r = mid-1; //找最小 37 } 38 else l = mid+1; 39 } 40 if (ans==-1) printf("No Solution!"); 41 else printf("%d",ans); 42 return 0; 43 }