您的位置:首页 > 其它

[POI 2012]Cloakroom(DP)

2015-05-15 21:57 190 查看

题目链接

http://main.edu.pl/en/archive/oi/19/sza

题目大意

有n件物品,每件物品有三个属性a[i], b[i], c[i] (a[i]<b[i]a[i])。

再给出q个询问,每个询问由非负整数m, k, s组成,问是否能够选出某些物品使得:

1. 对于每个选的物品i,满足a[i]<=m且b[i]>m+s。

2. 所有选出物品的c[i]的和正好是k。

思路

如果对于每次询问都从头开始做背包的话,那么肯定TLE。

考虑离线处理,一次背包回答所有的询问。对每个询问按照mm升序排序,对每个物品按照aa升序排序。然后开始做背包DP,维护当前要加入的物品jj,依次枚举询问ii,然后按照之前排序的顺序依次加入物品。用f[i][j]f[i][j]表示前ii个物品,在满足a≤ma \leq m的前提下,凑出体积kk的话,选出的物品里的bb最小值最大是多少。这个DP和一般的背包DP非常相似,因此我就不需作过多赘述了。之前的DP方程也可以和一般的背包DP一样用滚动数组优化成一维空间。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 1100
#define MAXK 110000
#define MAXQ 1100000
#define INF 0x3f3f3f3f

using namespace std;

int n,q;

struct Thing
{
int a,b,c;
}things[MAXN];

struct Query
{
int m,k,s,id;
}query[MAXQ];

bool ans[MAXQ];

bool cmp_thing(Thing a,Thing b)
{
return a.a<b.a;
}

bool cmp_query(Query a,Query b)
{
return a.m<b.m;
}

int f[MAXK];

int main()
{
int maxx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&things[i].c,&things[i].a,&things[i].b);
scanf("%d",&q);
for(int i=1;i<=q;i++)
query[i].id=i,scanf("%d%d%d",&query[i].m,&query[i].k,&query[i].s),maxx=max(maxx,query[i].k);
sort(things+1,things+n+1,cmp_thing);
sort(query+1,query+q+1,cmp_query);
f[0]=INF;
for(int i=1,j=1,sum=0;i<=q;i++) //回答第i个询问,当前决策是否放入第j个物品
{
for(;j<=n&&things[j].a<=query[i].m;sum+=things[j].c,j++)
for(int k=min(maxx,sum);k>=0;k--)
if(f[k])
f[k+things[j].c]=max(f[k+things[j].c],min(things[j].b,f[k]));
ans[query[i].id]=f[query[i].k]>(query[i].m+query[i].s);
}
for(int i=1;i<=q;i++)
printf("%s\n",ans[i]?"TAK":"NIE");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: