P1854 花店櫥窗佈置
題目描述
某花店現有$F$束花,每一束花的品種都不一樣,同時至少有同樣數量的花瓶,被按順序擺成一行,花瓶的位置是固定的,從左到右按$1$到$V$順序編號,$V$是花瓶的數目。花束可以移動,並且每束花用$1$到$F$的整數標識。如果$I < J$,則花束$I$必須放在花束$J$左邊的花瓶中。例如,假設杜鵑花的標識數為$1$,秋海棠的標識數為$2$,康乃馨的標識數為$3$,所有花束在放入花瓶時必須保持其標識數的順序,即杜鵑花必須放在秋海棠左邊的花瓶中,秋海棠必須放在康乃馨左邊的花瓶中。如果花瓶的數目大於花束的數目,則多餘的花瓶必須空,即每個花瓶只能放一束花。
每個花瓶的形狀和顏色也不相同,因此,當各個花瓶中放入不同的花束時,會產生不同的美學效果,並以美學值(一個整數)來表示,空置花瓶的美學值為0。在上述的例子中,花瓶與花束的不同搭配所具有的美學值,可以用如下的表格來表示:
花瓶1 花瓶2 花瓶3 花瓶4 花瓶5
杜鵑花 $7\ 23\ -5\ -24\ 16$
秋海棠 $5\ 21\ -4\ 10\ 23$
康乃馨 $-21\ 5\ -4\ -20\ 20$
根據表格,杜鵑花放在花瓶$2$中,會顯得非常好看,但若放在花瓶$4$中,則顯得很難看。
為了取得最佳的美學效果,必須在保持花束順序的前提下,使花的擺放取得最大的美學值,如果具有最大美學值的擺放方式不止一種,則輸出任何一種方案即可。
輸入格式
輸入檔案的第一行是兩個整數$F$和$V$,分別為花束數和花瓶數$(1\leqslant F\leqslant 100,F\leqslant V\leqslant 100)$。接下來是矩陣$A_{i,j}$,它有$I$行,每行$J$個整數,$A_{i,j}$表示花束$I$擺放在花瓶$J$中的美學值。
輸出格式
輸出檔案的第一行是一個整數,為最大的美學值;接下來有F行,每行兩個數,為那束花放入那個花瓶的編號。
樣例資料
輸入
3 5 7 23 -5 -24 16 5 21 -4 10 23 -21 5 -4 -20 20
輸出
53 2 4 5
分析
因為題中說當前插花的花瓶在上一個插花的花瓶以後,很容易想到數字三角形。那麼原題就可以變為在一個矩陣中只能向右下走,求經過的矩陣元素的和的最大值。最後遞迴輸出路徑。注意,初始化$Dp=INF,Dp_{0,i}=0$,狀態轉移方程$$Dp_{i,j}=max\left \{Dp_{i,j},Dp_{i-1,k-1}+G_{i,k}\right \}$$
程式碼
#include <bits/stdc++.h> #define Enter puts("") #define Space putchar(' ') #define INF 1e9 using namespace std; typedef long long ll; typedef double Db; inline ll Read() { ll Ans = 0; char Ch = getchar() , Las = ' '; while(!isdigit(Ch)) { Las = Ch; Ch = getchar(); } while(isdigit(Ch)) { Ans = (Ans << 3) + (Ans << 1) + Ch - '0'; Ch = getchar(); } if(Las == '-') Ans = -Ans; return Ans; } inline void Write(ll x) { if(x < 0) { x = -x; putchar('-'); } if(x >= 10) Write(x / 10); putchar(x % 10 + '0'); } int G[105][105]; int Dp[105][105]; void Print(int i , int j) { if(i == 0) return; int n = i; while(Dp[i][n] != j) n++; Print(i - 1 , j - G[i][n]); Write(n) , Space; } signed main() { int f = Read() , v = Read(); for(int i = 1; i <= f; i++) for(int j = 1; j <= v; j++) G[i][j] = Read(); memset(Dp , 128 , sizeof(Dp)); for(int i = 0 ; i <= 101; i++) Dp[0][i] = 0; for(int i = 1; i <= f; i++) for(int j = i; j <= v - f + i; j++) for(int k = 1; k <= j; k++) Dp[i][j] = max(Dp[i][j] , Dp[i - 1][k - 1] + G[i][k]); Write(Dp[f][v]) , Enter; Print(f , Dp[f][v]); return 0; } /* 3 5 7 23 -5 -24 16 5 21 -4 10 23 -21 5 -4 -20 20 */