【队内胡策 11.3】 T3

来源:互联网 发布:网络拓扑图常用图标 编辑:程序博客网 时间:2024/05/28 09:33

我以为是个DP啊,而且考试的时候没明白这里的二维背包指的是什么(回去重修语文)

这里写图片描述

其实是个贪心,前缀和+枚举?

对于一个n * m的格子(也就是背包),如果只放进大小为3 * 1的物品,一般情况下可以放进n * m/3种。特殊情况:n或m为2,且另一个%3==2,格子会剩下4个,只能用1 * 2的来填满,所以最多放(n*m-4)/3个。如果知道了放几个1 * 3的格子,就可以O(1)算出1 * 2的物品可以放几个,也就是剩余格子数量除以2。

这样,可以枚举1 * 3的物品放几个,然后算出1 * 2的物品,同时贪心的思想,把两种物品按照价值由大到小排序,预处理前缀和,O(1)查询放任意多少物品的最大总价值。

特判: 2 * 2的格子

PS:
对于任意N * M的格子,最多放进的1 * 3物品的数量证明,我不是很清楚qwq。自己想了想大概是这样:
由于剩下的格子一定组成矩形(如果不是矩形,就不是按照最优摆法摆的),这个矩形如果有一个边长为3的情况,就还会放下更多的物品,所以边长最大为2,这样形成的矩形有三种,1 * 1,2 * 2,1 * 2,除了2 * 2的特殊情况,设剩余格子面积为s,s最大为2,其他两种填上的1 * 3的物品数一定是(N * M-s)/3,由于s<3,故这个值相当于(N * M/3)下取整。而且剩下的格子的面积s除以二就是可以放上的1 * 2的物品的数量

大家讨论这个问题的时候,关于5 * 5的格子,放下8个的方式有点特殊,是这样的:
这里写图片描述
所以这个结论还是对的

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=10000+10;int t,n,m,n2,n3,maxx,last,ans;int f2[maxn],f3[maxn];bool cmp(int x,int y){    return x>y;}int main(){    scanf("%d",&t);    while(t--)    {        ans=0;        scanf("%d%d%d%d",&n,&m,&n2,&n3);        for(int i=1;i<=n2;++i) scanf("%d",&f2[i]);        for(int i=1;i<=n3;++i) scanf("%d",&f3[i]);        sort(f2+1,f2+n2+1,cmp);        sort(f3+1,f3+n3+1,cmp);        for(int i=1;i<=n2;++i) f2[i]+=f2[i-1];        for(int i=1;i<=n3;++i) f3[i]+=f3[i-1];        if((m%3==2)&&(n%3==2)&&(m==2||n==2)) maxx=(m*n-4)/3;        else maxx=(m*n)/3;        maxx=min(maxx,n3);        if(m==2&&n==2) ans=f2[2];        else        for(int i=0;i<=maxx;++i)//别忘了不放3的情况         {            last=n*m-3*i;            ans=max(ans,f3[i]+f2[min(last>>1,n2)]);        }        printf("%d\n",ans);    }    return 0;}
原创粉丝点击