動態規劃 擺花 題解

Tido發表於2019-07-26

剛剛卡出了這道動態規劃題,特此來發一筆題解啦~

 

題目內容如下

1123: NOIP2012普及組第3題 擺花

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 16  解決: 10
[提交] [狀態] [討論版] [命題人:外部匯入]

題目描述

  小明的花店新開張,為了吸引顧客,他想在花店的門口擺上一排花,共m盆。通過調查顧客的喜好,小明列出了顧客最喜歡的n種花,從1到n標號。為了在門口展 出更多種花,規定第i種花不能超過ai盆,擺花時同一種花放在一起,且不同種類的花需按標號的從小到大的順序依次擺列。試程式設計計算,一共有多少種不同的擺 花方案。


【輸入輸出樣例說明】
  有2種擺花的方案,分別是(1,1,1,2),(1,1,2,2)。括號裡的1和2表示兩種花,比如第一個方案是前三個位置擺第一種花,第四個位置擺第二種花。

 

輸入

  輸入檔案共2行。第一行包含兩個正整數n和m,中間用一個空格隔開。第二行有n個整數,每兩個整數之間用一個空格隔開,依次表示a1、a2、……an


【資料範圍】
對於20%資料,有0<n≤8,0<m≤8,0≤ai≤8;
對於50%資料,有0<n≤20,0<m≤20,0≤ai≤20;
對於100%資料,有0<n≤100,0<m≤100,0≤ ai≤100。

 

輸出

  輸出只有一行,一個整數,表示有多少種方案。注意:因為方案數可能很多,請輸出方案數對1000007取模的結果。

 

樣例輸入

2 4
3 2

 

樣例輸出

2

 

來源/分類

 

 

說實話 在剛剛看到這道題的時候,我的表情是完全僵硬的

 

 

那麼這一道題到底咋整!?

 

這一道題看到對1000007取模,就已經能夠明顯地看出來這道題的正解 是 動態規劃 

爆搜根本不行

 

我們先來整理一下題意 完全理解題目的含義是做題的第一步

 

本題說開了一個花店

要在門口擺一些花Flower~

 

一共有n種不同的花     總共m盆花   第 i 種花最多能擺ai

題目是看明白了 很明顯題意已經擺在我們的面前

 

我本人其實dp也剛入門 先來談一下我個人的非官方想法吧^_^

 

首先你在dp種肯定要用到ai 這個東西 

那麼你的 f 陣列肯定有一維是跟這個 i 是要掛鉤的  

i <= n

也就是說你的 f 陣列要有一維是 i 表示花的種類

 

憑直覺(O(∩_∩)O哈哈~)題目中有n和m

n的那一維有了

還要和m掛一點鉤鴨

那就再加一維 j 表示花的數量

 

寫到這裡其實也只都是一些籠統的通俗的概述

我們來正八經講一下接下來該怎麼辦吧

 

f [ i ] [ j ] 到底表示什麼呢

我的想法是   前 i 種花擺 j 盆的總方案數

這個其實還是比較好理解的

為甚麼非要前 i 種?這樣子因為題目問的是總方案數  你肯定要從 擺前1種 前2種 前3種 一直擴充套件 推推推推推 最好到前n種答案就出來啦

擺j盆就和剛才“憑直覺”的解釋一致啦就不多做解釋了

 

那麼狀態轉移方程該咋寫??

這困擾了我好久

我們先來寫寫看

 在擺第前 i 種花的時候,你肯定是從前 i-1種花 的f陣列的值推過來的對吧

那j怎麼推的?這個就不能直接簡單地轉移了

想想看假如擺前i-1種花的時候 你一共擺了x盆花

那麼現在你肯定是擺x +1 x+2 x+3.。。。盆

那麼我們只需要在轉移的時候再新增一層迴圈列舉多新增的盆數就行了

 

那麼當前這種花你最多也就放 j 盆或者a[i]盆

我們把j 和 a[i] 取一個更小的來作為第三層迴圈的範圍

還是粘一段程式碼稍微看看吧

三層迴圈搞定

當然你還要來點預處理才能跑起來啊

 

也很好理解 只放前1種花的時候 無論擺幾盆都只有一種方案

然後放前i種 但如果只放0盆 那方案當然也只有一種‘

這些預處理都是在dp的過程中 進行擴充套件是要用到的  可以手動模擬一波試試看

 

所以程式碼完整如下

 

 

#include<bits/stdc++.h>
using namespace std;
int a[105];
int f[105][105];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    //f[i][j]表示前i種花擺j盆花的總方案數
    for(int i=1;i<=a[1];i++)
        f[1][i]=1;
    for(int i=1;i<=n;i++)
        f[i][0]=1;
    for(int i=1;i<=n;i++)    
        for(int j=1;j<=m;j++)
            for(int k=0;k<=min(j,a[i]);k++)
                f[i][j]=(f[i][j]+f[i-1][j-k])%1000007;
    cout<<f[n][m]; 
    
    return 0;
}

 

 加油 我們一起進步

 

 

看完這篇嘔心瀝血寫完的文章

點個贊再走吧

~

 

相關文章