藍橋杯 試題 歷屆試題 圖形排版
阿新 • • 發佈:2020-08-10
問題描述
小明需要在一篇文件中加入 N 張圖片,其中第 i 張圖片的寬度是 Wi,高度是 Hi。
假設紙張的寬度是 M,小明使用的文件編輯工具會用以下方式對圖片進行自動排版:
1. 該工具會按照圖片順序,在寬度 M 以內,將盡可能多的圖片排在一行。該行的高度是行內最高的圖片的高度。例如在 M=10 的紙張上依次列印 3x4, 2x2, 3x3 三張圖片,則效果如下圖所示,這一行高度為4。(分割線以上為列標尺,分割線以下為排版區域;數字組成的矩形為第x張圖片佔用的版面)
2. 如果當前行剩餘寬度大於0,並且小於下一張圖片,則下一張圖片會按比例縮放到寬度為當前行剩餘寬度(高度向上取整),然後放入當前行。例如再放入一張4x9的圖片,由於剩餘寬度是2,這張圖片會被壓縮到2x5,再被放入第一行的末尾。此時該行高度為5:
3. 如果當前行剩餘寬度為0,該工具會從下一行開始繼續對剩餘的圖片進行排版,直到所有圖片都處理完畢。此時所有行的總高度和就是這 N 張圖片的排版高度。例如再放入11x1, 5x5, 3x4 的圖片後,效果如下圖所示,總高度為11:
現在由於排版高度過高,圖片的先後順序也不能改變,小明只好從 N 張圖片中選擇一張刪除掉以降低總高度。他希望剩餘N-1張圖片按原順序的排版高度最低,你能求出最低高度是多少麼? 輸入格式 第一行包含兩個整數 M 和 N,分別表示紙張寬度和圖片的數量。
接下來 N 行,每行2個整數Wi, Hi,表示第 i 個圖大小為 Wi*Hi。
對於30%的資料,滿足1<=N<=1000
對於100%的資料,滿足1<=N<=100000,1<=M, Wi, Hi<=100
輸出格式
一個整數,表示在刪除掉某一張圖片之後,排版高度最少能是多少。
樣例輸入
4 3
2 2
2 3
2 2 樣例輸出 2 樣例輸入 2 10
4 4
4 3
1 3
4 5
2 1
2 3
5 4
5 3
1 5
2 4 樣例輸出 17
解題思路:小明刪除第 i 張圖片時,第 1 到 i-1 張圖片的排版不變,只有第 i+1 到 N 張圖片的排版改變。並且如果用一個數組儲存以第k張圖片開始排版圖片的高度,計算第 i+1 到 N 張圖片 改變後高度時就不需要全部計算,而只需要計算在換行之前受影響的高度+以之後圖片開始排版的高度。 實現程式碼:
假設紙張的寬度是 M,小明使用的文件編輯工具會用以下方式對圖片進行自動排版:
1. 該工具會按照圖片順序,在寬度 M 以內,將盡可能多的圖片排在一行。該行的高度是行內最高的圖片的高度。例如在 M=10 的紙張上依次列印 3x4, 2x2, 3x3 三張圖片,則效果如下圖所示,這一行高度為4。(分割線以上為列標尺,分割線以下為排版區域;數字組成的矩形為第x張圖片佔用的版面)
2. 如果當前行剩餘寬度大於0,並且小於下一張圖片,則下一張圖片會按比例縮放到寬度為當前行剩餘寬度(高度向上取整),然後放入當前行。例如再放入一張4x9的圖片,由於剩餘寬度是2,這張圖片會被壓縮到2x5,再被放入第一行的末尾。此時該行高度為5:
3. 如果當前行剩餘寬度為0,該工具會從下一行開始繼續對剩餘的圖片進行排版,直到所有圖片都處理完畢。此時所有行的總高度和就是這 N 張圖片的排版高度。例如再放入11x1, 5x5, 3x4 的圖片後,效果如下圖所示,總高度為11:
現在由於排版高度過高,圖片的先後順序也不能改變,小明只好從 N 張圖片中選擇一張刪除掉以降低總高度。他希望剩餘N-1張圖片按原順序的排版高度最低,你能求出最低高度是多少麼? 輸入格式 第一行包含兩個整數 M 和 N,分別表示紙張寬度和圖片的數量。
接下來 N 行,每行2個整數Wi, Hi,表示第 i 個圖大小為 Wi*Hi。
對於30%的資料,滿足1<=N<=1000
2 2
2 3
2 2 樣例輸出 2 樣例輸入 2 10
4 4
4 3
1 3
4 5
2 1
2 3
5 4
5 3
1 5
2 4 樣例輸出 17
解題思路:小明刪除第 i 張圖片時,第 1 到 i-1 張圖片的排版不變,只有第 i+1 到 N 張圖片的排版改變。並且如果用一個數組儲存以第k張圖片開始排版圖片的高度,計算第 i+1 到 N 張圖片 改變後高度時就不需要全部計算,而只需要計算在換行之前受影響的高度+以之後圖片開始排版的高度。 實現程式碼:
#include<cstdio> #include<algorithm> using namespace std; const int Max_N = 100000; const int INF = 1000000; struct paper//圖片結構體 { int w; int h; paper(int w_,int h_){//建構函式 w = w_; h = h_; } paper(){} }; paper P[Max_N+1]; //輸入 int N,M; int Rev[Max_N+2];//Rev[i]: 將 i-N 順序加入最後的高度 void add(paper &p,int k)//在p的基礎上加入第k個圖片 p記錄當前佔用寬度和高度(這裡p到代表某一行排列) { //加入時分兩種情況考慮 if( p.w+P[k].w <= M )//加入圖片寬度小於等於剩餘寬度 (這時圖片不需要收縮) { p.w += P[k].w; p.h = max( p.h, P[k].h ); } else {//加入圖片寬度>剩餘寬度 int w = M - p.w;//剩餘寬度 p.h = max( p.h, ((w*P[k].h-1)/P[k].w)+1 );// wi/hi=w/h->h=w*hi/wi (-1,+1是處理向上取整) p.w = M; } } int getRev(paper p,int k)//在加入p的基礎上加上k-N後排版的高度 { while( p.w<M && k<=N ) { add(p,k); k++; } return p.h + Rev[k]; } void solve() { for(int i=N; i>=1; i--)//初始化Rev[] { paper p(0,0); Rev[i] = getRev(p,i); } paper p(0,0); int res = INF, h = 0; for(int i=1; i<=N; i++) {//每次去掉第i個圖片 res = min( res, h + getRev(p,i+1) );//h:1-i-1的高度, getRev(p,i+1):i+1-N高度 add(p,i); if( p.w==M ) { h += p.h;//更新當前排版高度 p.w = p.h = 0;//下一行 } } printf("%d\n",res); } int main() { scanf("%d%d",&M,&N); for(int i=1; i<=N; i++){ scanf("%d%d",&P[i].w,&P[i].h); } solve(); return 0; }
//參考連結https://blog.csdn.net/qq_20087731/article/details/106262655