1. 程式人生 > 其它 >P1854 花店櫥窗佈置

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
*/