HihoCoder-1365 图片排版(想法题)

题意

一张宽度为 m 的纸,现在要插入 n 张图片,第 i 张图片的宽度为 w i ,高度为 h i ,插入的方法如下:
1.当这张图片可以在同行插入,则插至同行;
2.如果这一行宽度已满,调至下一行;
3.否则将图片等比例压缩填满此行(高度向上取整)。
如现在有 7 张图片: 3 × 4 , 2 × 2 , 3 × 3 , 4 × 9 , 1 × 1 , 5 × 5 , 3 × 4 宽度 m 10 将变成如下的图:

0123456789
----------
        44
111     44
111  33344
1112233344
1112233344
5555555555
66666
66666777
66666777
66666777
66666777

现在需要舍弃一张图片使得总高度最小,求高度最小值。
1 n 100000
1 M , w i , h i 100

思路

比较好想的方法是枚举舍弃哪一张图片,但是时间上不允许,考虑到填满某一行后,后面的插入会多次重复计算,可以倒序预处理出一个数组 t t i 表示 i 号图片及其后的图片另起一行插入得到的高度。然后按顺序枚举哪一张图片不选,同时将选的图片插入。预处理和求解可以共用一个“放满一行”的函数。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;
int t[100003];
int n,m;

struct pic
{
    int w,h;
    void zipped(int res)
    {
        (*this)=(pic){res,(h*res+w-1)/w};
    }
}a[100003];
struct line
{
    int w,h;
    line(){w=0,h=0;}    //如果需要同时使用强转和构造,需要重载两个构造函数 
    line(int _w,int _h){w=_w,h=_h;}
    line operator +(pic _)
    {
        if(w+_.w>m)
            _.zipped(m-w);
        return (line){w+_.w,max(h,_.h)};
    }
    bool full(){return w==m;}
    void clr(){w=h=0;}
};

int push_till_full(line alpha,int k)
{
    for(;k<=n && !alpha.full();k++)
        alpha=alpha+a[k];
    return t[k]+alpha.h;
}

int main()
{
    int ans=2e9;
    scanf("%d%d",&m,&n);
    FOR(i,1,n)scanf("%d%d",&a[i].w,&a[i].h);
    DOR(i,n,1)t[i]=push_till_full((line){0,0},i);
    line alpha;
    int per=0;
    FOR(i,1,n)
    {
        ans=min(ans,per+push_till_full(alpha,i+1));
        alpha=alpha+a[i];
        if(alpha.full())
        {
            per+=alpha.h;
            alpha.clr();
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/paulliant/article/details/80812732