dp(背包)
Cloakroom
题目描述
- 有n件物品,每件物品有三个属性a[i],b[i],c[i](a[i]<b[i])
- q个询问,每个询问由非负整数m,k,s组成,问是否能够选出某些物品使得:
- 对于每个选的物品i,满足a[i]<=m且b[i]>m+s
- 所有选出物品的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 }