本帖背景:最近博主在练习01背包的问题,发现一道题结合了01背包和二分算法,令本蒟蒻大受启发,特此来水一篇分享
#Knowledge reserve(知识储备)
##01背包
经典的01背包问题是给定一定数量的物品和限定大小的背包,每个物品有一定的价值,要求在不超过背包容量的情况下最多能装多少价值的物品
我们先给出一般化的二维背包方程dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]] + v[i])
假如有3个物品,背包容量为8 物品的重量和价值分别为3,6 4,7 5,8
当我们循环到第二个物品是dp[2][8]就是把两个物品都考虑进去价值为13
但是当我们循环到第3个物品时背包的容量不够,但由于把这个物品放入背包仍然属于一种情况
为了不漏解dp[3][8] = max(dp[2][8],dp[2][8-5] + 8)
我们在这里把背包进行分割,显然背包容量为3时我们把物品1放入了背包,从这部分背包递推到背包容量为8时的情况是最优解
其他的情况也可以同样类比,这样我们既能把每一种情况都考虑到又可以找到最优的解
核心代码如下
for(i = 1; i <= m; ++i)//枚举个数
for(j = 1; j <= n; ++j)//枚举容量
{
if(w[i] <= j)
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]);
else
dp[i][j] = dp[i - 1][j];
}
好扒,先给你5分钟思考的时间我们再继续
###01背包空间的优化
接下来我们考虑把01背包的二维数组从二维优化到1维
核心dp[i][j] -----> dp[j]
dp[j] = max(dp[j],dp[j-w[i]] + v[i])
for(i = 1; i <= m; ++i)
for(j = 1; j <= n; j--)
{
if(w[i] <= j)
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);//这里dp[j]储存的是上一状态
}
嗯,不错,大部分都是正确的,但还需要注意一点————————循环顺序
试着思考正序循环我们可能会面临这样一个问题,如果背包中原本有个物品重量为k的物品,当j = k的时候,我们会面临是否将这个特殊的物品放入背包,
而当j为2k的时候我们将会面临同样的选择
如果在两次选择中我们都发现把这个物品放入背包的价值更大,接下来会发生什么?
显然我们把一个物品放入了两次,但是一个物品只能放入一次,和题意不符
所以我们需要把循环顺序颠倒一下,代码如下:
for(int i = 0;i < n;i ++){
int v, w;
cin >> v >> w;
for(int j = V;j >= v;j --)//显然如果j
01背包的讲解就到这里就结束了,01背包还有很多扩展比如多重背包,完全背包等等,这里暂时不去讨论这些
接下来我们看看其他的
##二分
在临界点左边的所有数都满足或不满足某一条件,右边的数都不满足或满足某一条件(也就是跟之前的相反)
while(l < r)
{
int mid = l + r >> 1;
if(check(mid))//检验中间的值是否满足要求
l = mid + 1;
else
r = mid;
}
下面给出这样的一个例子来帮助我们理解
给定一组数字 1 2 3 3 4 5共6个数字,要求找到第一个大于等于3的数字
显然这个数组满足我们的先决条件,一部分小于3,一部分不小于3。
根据二分算法的性质我们理论上可以找到这个临界点
我们的答案在1~6中选取,(这里指的是各个数的编号),所以l左边界就是1,r右边界是6。
第一次mid是3,第3个数满足要求,所以但是由于要找第一个数,此时这个数可能是第一个也可能不是,所以右边界要变成mid;然后再继续判断直到找到我们想要的临界值
好了,现在我们有了一定的知识储备,可以来看一道01背包和二分结合的例子:
##例题
本题来源于洛谷P2370(看懂了可以自行去ac)
###题目描述
你找 yyy2015c01 借到了这个高端的 U 盘,拷贝一些重要资料,但是你发现这个 U 盘有一些问题:
为了选择要备份哪些文件,你给所有文件设置了一个价值 Vi,你希望备份的文件总价值不小于 p。
但是很快你发现这是不可能的,因为 yyy2015c01 的传输接口太小了,你只有花钱买一个更大的接口(更大的接口意味着可以传输更大的文件,但是购买它会花费更多的钱)。
注意:你的文件不能被分割(你只能把一个文件整个的传输进去,并储存在U盘中),
你放在 U 盘中文件的总大小不能超过 U 盘容量。
现在问题来了:你想知道,在满足 U 盘中文件价值之和不小于 p 时,最小需要多大的接口。
###输入格式
第 1 行,三个正整数 n,p,S 分别表示文件总数,希望最小价值 p ,硬盘大小。
接下来 n 行,每行两个正整数 Wi,Vi
表示第 i 个文件的大小和价值。
###输出格式
输出一个正整数表示最小需要的接口大小。
如果无解输出 No Solution!。
###输入
3 3 5
2 2
1 2
3 2
###输出
2
###输入
2 3 505
1 2
500 1
###输出
500
###输入
3 3 2
2 2
1 2
3 2
###输出
No Solution!
###输入
4 5 6
5 1
5 2
5 3
1 1
###输出
No Solution!
###思路解析
通过题目中的关键词比如限定了大小,价值等因素可以初步判断可能是一个01背包的问题,但是由于题目中还给了另外一个因素就是要求所得得价值必须超过所给得价值,而且我们还要找一个最小的接口
这些信息给了我们很大的混淆
我们每次选完形成的一种选法所得的接口大小是背包中所有接口的最大大小,然后我们还要把这所有符合要求的选法选出来,从这些接口中找到一个最小的,如果考虑表示最小的接口,显然维护起来非常困难,而且由于题目所给的价值数很大,难以用数组储存
我们能从刚开始的输入中知道所有的端口,而正确答案的端口一定会在这个区间之间。但是题目所给的端口不一定是来连续的。比如三个端口80,90,100;我们只知道答案是这三个端口中的一个,但并不是81,82等等;因此我们设置二分元素是正确答案小于等于我们所二分的端口大小。
这样做的话显然二分区间会出现一个临界点,而临界点左边不满足二分的要求,临界点的右边满足二分的要求
所以我们只需要二分这个区间,进而去逼近答案
while (minn < maxx)
{
midd = minn + maxx >> 1;
if (dp(midd) >= m)//dp函数详情请继续往下看解析
maxx = midd;
else
minn = midd + 1;//minn和maxx分别是左右边界
}
因此我们需要每次判断时都对这个端口做一次01背包,如果有比他大的端口一定不选(因为选了的话最大的端口就会发生改变),
int dp(int x)
{
for(int i = 0; i <= s; ++i)
Matrix[i] = 0;
for(int i = 1; i <= n; ++i)
{
if (x != -1 && x < w[i])//如果碰到比他大得就不考虑,这里特殊一种-1得情况是为了判定是否有解,-1得情况就是求这个背包在没有限制条件下得最大价值
continue;
for (int j = s; j >= w[i]; --j)
Matrix[j] = max(Matrix[j], Matrix[j - w[i]] + v[i]);
}
return Matrix[s];
}
小于等于它的就可以放入背包中。只要存在一种解法,能够使得所选方案凑出来的价值数大于题目所给的价值数,那么显然这个端口是满足要求的,右区间向前移动,(如果我们已知小于等于x的端口能凑出满足题意得价值,那么大于x得数一定会包含x得这种方案,因此后面01背包求出来得价值只有可能比他高)
#include
#include
using namespace std;
typedef long long ll;
#define fi(a, b) for (int i = a; i <= b; ++i)
#define fr(a, b) for (int i = a; i >= b; --i)
using pii = pair;
const int N = 1e3 + 5;
const int M = 1e5 + 5;
int w[N], v[N];
int n, m, s;
int Matrix[M];
//#define DEBUG
int dp(int x)
{
fi(0, s)
Matrix[i] = 0;
fi(1, n)
{
if (x != -1 && x < w[i])
continue;
for (int j = s; j >= w[i]; --j)
Matrix[j] = max(Matrix[j], Matrix[j - w[i]] + v[i]);
}
return Matrix[s];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
#ifdef DEBUG
//freopen(D:\in.txt,r,stdin);
#endif
cin >> n >> m >> s;
int minn = 0x3f3f3f3f;
int maxx = -minn;
fi(1, n)
{
cin >> w[i] >> v[i];
minn = min(minn, w[i]);
maxx = max(maxx, w[i]);
}
int midd;
while (minn < maxx)
{
midd = minn + maxx >> 1;
if (dp(midd) >= m)
maxx = midd;
else
minn = midd + 1;
}
if (dp(-1) < m)
cout << "No Solution!" << endl;
else
{
cout << minn << endl;
}
return 0;
}
顺便贴上博主得一些hack样例(之前用二维背包只能骗70分┭┮﹏┭┮)
input
13 62 124
20 13
20 19
20 13
34 13
49 133
43 1
20 22
20 30
36 30
36 4
42 13
37 11
44 1
37 16
21 10
36 19
49 27
27 5
24 11
23 13
50 25
44 27
37 12
48 1
output
20
input
840 269 909
108 240
978 297
474 362
999 994
121 72
704 261
300 285
281 239
882 563
486 972
933 295
131 280
741 374
457 78
44 15
45 12
870 749
331 843
53 61
241 584
76 195
522 955
910 695
877 917
737 228
256 443
357 4
229 98
487 648
352 416
363 559
136 205
880 634
508 874
61 136
730 78
861 203
420 919
692 605
60 96
789 809
670 301
242 923
994 586
849 700
750 483
461 615
738 944
474 897
610 953
759 303
260 579
681 347
302 741
754 119
383 253
860 251
484 340
451 93
176 592
960 711
817 462
477 429
564 598
748 728
684 889
987 590
927 826
881 759
544 339
581 728
263 535
662 217
878 823
778 378
442 246
101 44
307 217
115 349
182 68
980 132
895 300
564 407
445 147
354 447
705 595
171 58
674 617
589 594
758 366
632 779
130 170
153 478
547 37
642 860
129 164
790 364
74 168
565 997
939 220
478 651
135 80
872 671
253 421
664 473
109 136
491 675
120 106
225 464
660 403
491 428
509 462
640 847
920 112
496 168
73 176
127 204
567 341
570 578
393 156
873 286
647 627
193 282
1000 154
648 910
465 868
837 54
629 488
940 953
264 740
417 483
159 417
960 748
656 146
200 253
611 125
61 16
858 559
866 102
566 6
720 357
973 364
725 259
883 461
234 259
520 780
176 642
409 352
31 0
926 231
710 606
48 88
202 427
566 956
607 666
125 388
129 85
535 907
172 707
921 456
971 336
817 484
373 157
597 923
454 918
786 754
63 31
980 719
257 132
331 665
952 522
644 88
506 388
517 446
339 651
571 770
751 629
866 914
390 953
676 441
194 379
203 284
55 38
142 174
261 89
617 332
321 11
156 490
699 994
109 316
528 210
569 416
391 761
416 759
400 441
435 56
272 401
531 746
288 381
509 987
376 34
395 274
589 728
730 462
677 494
698 854
916 299
950 672
542 231
792 770
680 355
918 456
898 517
953 336
959 531
90 210
152 436
281 665
265 143
535 742
721 651
411 365
403 880
924 614
358 971
495 814
261 442
983 910
988 325
200 372
310 898
304 412
212 25
1000 831
527 302
243 247
455 566
218 520
576 800
305 580
481 143
735 553
933 293
276 621
92 22
573 843
156 183
533 156
66 111
420 565
777 52
911 162
210 692
721 516
761 407
381 259
903 361
901 663
990 467
848 231
881 5
585 870
949 501
707 607
230 18
183 544
142 405
637 804
229 103
587 1
204 49
994 100
456 854
598 165
529 564
217 174
981 578
244 147
710 629
184 751
713 779
129 316
164 157
758 766
634 456
136 27
83 133
538 559
363 691
476 566
739 743
642 912
446 988
746 949
924 833
344 634
811 197
594 859
930 371
335 66
889 154
81 71
658 843
692 648
672 21
689 975
485 694
270 244
56 10
553 209
414 924
565 781
908 788
702 423
967 429
915 40
183 468
112 95
591 793
255 392
891 245
757 69
688 679
643 446
342 715
779 573
458 937
192 150
75 118
727 924
542 282
177 115
709 524
769 105
47 17
319 407
455 726
956 455
720 405
969 880
842 650
473 583
755 389
848 329
972 961
602 27
854 182
885 746
362 161
347 568
675 926
464 553
555 675
36 24
901 141
816 763
982 834
341 481
94 87
528 510
747 727
576 393
468 918
285 452
993 764
87 131
951 170
485 984
62 85
881 844
74 131
529 3
669 498
796 861
535 798
527 337
299 939
802 143
863 398
74 118
190 191
236 881
828 637
417 258
790 533
739 291
89 122
355 52
272 209
84 132
816 342
871 560
158 283
173 508
229 936
577 899
242 631
389 848
165 152
486 182
488 260
750 574
378 546
576 397
698 109
425 864
62 0
505 443
836 364
929 2
162 598
288 874
278 329
324 728
813 644
472 779
196 408
708 291
821 657
202 324
178 3
98 256
382 660
793 849
603 297
843 200
429 403
216 396
902 852
508 343
687 528
68 91
906 84
797 714
347 624
915 217
109 297
845 281
129 256
546 77
856 273
173 580
863 539
297 327
904 537
648 449
862 791
133 264
285 196
679 273
869 539
545 205
817 787
767 222
929 499
989 930
789 576
969 508
593 624
504 326
408 172
888 778
231 69
248 509
393 213
366 616
965 308
536 319
100 87
846 838
304 704
226 442
895 491
756 338
458 494
150 17
295 496
962 671
59 98
738 962
366 461
231 69
762 280
287 361
355 724
592 344
861 289
339 988
600 970
294 115
806 951
412 284
536 466
630 962
669 965
71 205
402 105
523 651
697 912
543 528
927 189
742 580
185 256
445 669
938 902
979 884
814 149
922 533
668 425
983 413
648 954
883 547
999 484
991 160
475 906
482 132
468 331
82 231
789 22
439 547
238 325
221 778
138 517
272 380
292 44
622 832
775 316
425 385
250 231
411 316
795 589
868 499
409 616
46 54
299 905
85 252
387 282
518 566
488 518
416 570
328 249
924 154
542 117
721 867
626 99
123 61
577 826
173 14
721 881
473 679
168 438
544 858
126 119
246 87
915 52
562 189
787 126
456 210
361 77
810 320
594 537
955 16
375 601
53 107
777 139
569 835
179 436
506 80
96 323
119 220
331 540
898 11
492 413
359 798
214 16
960 366
179 62
857 448
461 867
562 923
511 66
952 280
743 742
640 361
807 936
981 858
164 521
374 841
699 149
174 161
484 231
644 736
908 23
558 35
129 404
758 666
927 210
533 958
507 375
851 338
571 6
432 256
205 318
317 434
540 236
219 722
475 113
264 898
30 0
306 235
634 797
469 398
86 243
610 914
650 0
915 376
151 422
74 84
970 12
43 62
966 115
693 533
904 495
649 123
469 449
702 119
529 970
92 261
55 89
240 345
226 800
746 907
970 167
561 202
573 423
356 116
456 17
806 962
267 577
113 136
463 0
903 767
355 527
95 247
222 44
459 658
714 571
101 80
364 895
897 468
364 169
934 952
190 495
165 468
284 946
647 390
643 250
52 57
457 969
475 462
769 501
304 957
288 600
679 364
225 804
600 208
233 241
342 13
110 261
720 518
225 752
585 469
143 242
357 532
297 341
942 846
310 56
904 822
482 689
773 100
446 350
276 178
384 717
937 581
162 161
267 637
394 596
42 21
764 353
736 539
870 875
616 721
250 900
353 718
147 512
415 499
127 266
194 416
940 903
621 161
228 114
521 188
225 109
902 86
268 169
89 152
507 619
193 72
197 488
554 266
540 715
538 49
320 780
544 685
483 467
763 868
424 161
967 615
693 325
447 990
901 490
756 825
714 806
881 303
556 625
589 637
86 220
227 320
320 262
148 6
987 617
853 797
916 546
606 704
945 574
286 749
908 875
98 221
227 934
247 931
588 706
33 0
347 945
126 346
210 663
988 976
267 146
660 676
514 539
708 518
979 628
309 753
647 715
628 967
455 644
251 117
729 843
696 713
270 352
313 906
925 954
171 462
182 443
681 867
58 89
619 469
850 364
860 848
654 651
886 715
326 639
119 440
86 121
675 0
682 297
305 475
342 872
604 97
178 249
455 780
70 96
857 280
145 207
690 78
396 147
621 338
277 520
306 177
97 48
526 133
953 760
177 268
750 558
74 55
382 748
155 568
836 121
638 468
822 369
720 597
44 17
130 219
531 700
582 16
402 196
367 868
201 46
52 24
559 224
514 139
990 811
664 271
165 299
81 112
783 111
450 0
932 398
510 169
576 16
279 216
378 26
637 43
204 745
502 25
426 832
166 123
834 946
235 735
926 250
840 699
724 704
777 806
59 14
609 493
666 128
976 52
897 0
191 103
443 868
53 56
output
48
今天的分享就到这里,感谢大家来拜访本蒟蒻的帖子~~