dp(背包)

                                                                                                            Cloakroom

题目描述

  • 有n件物品,每件物品有三个属性a[i],b[i],c[i](a[i]<b[i])
  • q个询问,每个询问由非负整数m,k,s组成,问是否能够选出某些物品使得:
  1. 对于每个选的物品i,满足a[i]<=m且b[i]>m+s
  2. 所有选出物品的c[i]和正好是k

输入格式

  • 第一行一个正整数n(n<=1000),接下来n行每行三个正整数,分别表示c[i],a[i],b[i](c[i]<=1000,1<=a[i]<b[i]<=1,000,000,000)
  • 下面一行一个正整数q(q<=1,000,000),接下来q行每行三个非负整数m,k,s(1<=m<=1,000,000,000,0<=k<=1,000,000,0<=s<=1,000,000,000)

输出格式

输出q行,每行为 " TAK" (yes )或"NIE " (no),第i行对应第i次询问的答案。

样例输入

5
6 2 7
5 4 9
1 2 4
2 5 8
1 3 9
5
2 7 1
2 7 2
3 2 0
5 7 2
4 1 5

样例输出

TAK
NIE
TAK
TAK
NIE

思路:首先:若只有第二种限制,则是一个裸的背包,所以,我们可以在01背包的基础上限制第一个条件
第二:限制a[i]<=m,将a[i]升序排列,将m也升序排列(所以需要离线操作,注意记录每个询问对应的序号,以便输出)
   第三:限制b[i]>m+s,将f[i]定义为装满容量为i的背包所有方案中每个方案最小b[i]的最大值(每个方案选最小b[i],确保方案中所有的b[i]都满足b[i]>m+s,因为一种方案中最小的b[i]都比m+s大,其他肯定也比m+s大
选最大值是因为每个容量只需一种方案满足即可,所以应选所有方案中最小b[i]的最大值更容易符合要求)
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=1000+10,inf=0x3f3f3f3f;
 5 int n,mm;
 6 int f[1000000+10];
 7 struct Node{
 8     int a,b,c;
 9     bool operator <(const Node &A)const{
10         return a<A.a;
11     }
12 }e[maxn];
13 struct Node1{
14     int m,k,s,id;
15     bool operator <(const Node1 &a)const{
16         return m<a.m;
17     }
18 }q[1000000+10];
19 int ans[1000000+10];
20 void solve(){
21     int j=1;
22     f[0]=inf;
23     for(int i=1;i<=mm;i++){
24         int m=q[i].m,k=q[i].k,s=q[i].s;
25         while(j<=n&&e[j].a<=m){//限制a[i]<=m,若e[j]不符合要求,跳出循环,当循环到下一个i时以前确定的f[i]值不变
26             for(int w=100000;w>=e[j].c;w--){
27                 f[w]=max(f[w],min(f[w-e[j].c],e[j].b));
28             }//01背包
29             j++;
30         }
31         if(f[k]>m+s) ans[q[i].id]=1;//若符合,则为真,注意ans的下标为查询的序号而不是排序之后的
32     }
33     for(int i=1;i<=mm;i++){
34         if(ans[i]) printf("TAK\n");
35         else printf("NIE\n");
36     }
37 }
38 int main(){
39     scanf("%d",&n);
40     for(int i=1;i<=n;i++){
41         scanf("%d%d%d",&e[i].c,&e[i].a,&e[i].b);
42     }
43     sort(e+1,e+1+n);//对a排升序
44     scanf("%d",&mm);
45     for(int i=1;i<=mm;i++){
46         scanf("%d%d%d",&q[i].m,&q[i].k,&q[i].s);
47         q[i].id=i;
48     }
49     sort(q+1,q+1+mm);//对m排升序
50     solve();
51     return 0;
52 }
View Code

 

 
posted @ 2020-07-19 15:55  ddoodd  阅读(147)  评论(0编辑  收藏  举报