題外廢話:
真的超級喜歡這道題
擺花【題目鏈結】
yy一提醒,我發現這道題和【洛谷p2089】 烤雞有異曲同工之妙(資料更大了更容易tle呢qwq)
solution1:(暴搜)
搜尋:關於搜尋就不用多介紹了吧,這裡是用了dfs:dfs函式中有兩個變數,rest和i分別表示還需要擺放多少盆花以及現在擺放到第幾種花了,因為我們是從0開始列舉,因此如果某種花我們不選擇,那就可以看做這種花選擇了0盆;
幾個返回條件:
1.rest==0時,記錄ans++(ans是全域性變數)return,不需要滿足rest==0&&i=n+1(因為只要rest被列舉完了就可以了,後面的花不擺放就好啦)
2.i==n+1時,return;為什麼是i=n+1呢,因為當i=n時,我們並沒有列舉第n種花擺放的盆數,如果現在就返回,顯然是會對結果造成很大的影響,進而影響整個結果;
核心語句:
其實就一句話:
for(int j=0;j<=a[i];j++)dfs(rest-j,i+1);
直接暴力dfs因為實際並沒有改變rest和i的值,所以我們連回溯都不需回溯;
以下是完整code:
code1:
#includeusingnamespace
std;
intn,m,ans,cnt;
int a[110],b[110
];void dfs(int rest/*
還需要擺多少盆花
*/,int i/*
n種花*/
)
if(i==n+1) return
;
if(rest<0) return
;
for(int j=0;j<=a[i];j++)
dfs(rest-j,i+1
);
return;}
intmain()
但是非常遺憾的是暴搜顯然不是正解,成功的tle了7個點(功成身退)
所以我們想到了記憶化搜尋:
solution2:(記憶化搜尋)
寫暴搜的原因是因為並不會正解dp,因此只好暴搜了,然後又知道暴搜妥妥的tle,所以在暴搜**完成之後,改成了記憶化:
大致思路還是沒有變,但dfs從沒有返回值變成了帶有返回值的dfs,當rest==0時(形成一種擺花條件時)return 1;否則return 0(對於最小子問題);對於每一次定義乙個ans(當然也可以開全域性然後每次重新賦值),列舉所有的擺花盆數,ans+=dfs(rest-j,i+1)[意思是對於某種花列舉所有可能的擺放盆數,統計剩餘的空位置的總方案數,表示某種花擺j盆的總方案數(可能有點不對是非常繞)],記憶化陣列b[i][rest]表示第i種花擺放前剩餘rest個空位置(沒有擺花)剩餘rest個位置擺花的方案數,當我們已經計算過這個方案數以後,就可以直接拿來用而不是總是遞迴炸掉了。所以加一句
if(b[i][rest]) return b[i][rest];
如何計算b[i][rest]以及每一步的ans:
其實樓上兩個東西是一回事,b[i][rest]=ans;
下面來看如何計算ans:首先列舉第i種花所有擺放盆數(0~a[i]),然後dfs(rest-j,i+1),不斷將求得的值加到ans裡,(ans記錄的是當前要擺第i種花,此時還剩rest(第i種花還沒擺)個位置時所有擺花的方案數)不要忘記取mod;
最後不要忘記return ans;
code2:
#includeusingnamespace
std;
long
long
n,m,cnt;
long
long a[1100],b[1100][1100
];const
int mod=1000007
;long
long dfs(long
long rest/*
還需要擺多少盆花
*/,long
long i/*
擺放n種花*/)
b[i][rest]=ans;
return
ans;
}int
main()
悄咪咪的粘上記憶化搜尋的模板:(來自oi-wiki)
intg[maxn];
intf(傳入數值)
intmain()
solution3:(正解-動態規劃)
q姓神仙的題解【題解】
定義二維陣列f[i][j]表示擺放i種花共j盆的最大方案數,初始狀態是:f[i][0]=1;(因為不管是哪種花,只要不擺放,方案數均為1)這裡雖然是二位陣列,但dp時需要三重迴圈第一重迴圈i表示擺放i種花,第二重迴圈j表示這i種花共擺放多少盆(顯然是1~m),第三重迴圈k,表示的是這種花擺放的盆數,(從0盆到a[i]盆),這裡的第三層迴圈要從j到j-a[i]進行列舉轉移方程就是f[i][j]+=f[i-1][k]%mod:
啥意思:
因為前i種花一共擺放j盆,那麼假設第i種花擺放k1(k1∈(0,a[k1])盆,那麼前面的i-1種花就擺放j-k1盆(所以第三層迴圈列舉的是前i-1種花擺放的方案數),那麼所有的方案數相加就是擺放i種花j盆的最大方案數;
最後的答案就是f[n][m]%mod;(最後要%mod防止超出答案)
code3:
#includeusingnamespace
std;
intn,m;
int a[110],f[110][110
];const
int mod=1000007
;int
main()
cout
}
真.end-
擺花 洛谷p1077
小明的花店新開張,為了吸引顧客,他想在花店的門口擺上一排花,共m盆。通過調查顧客的喜好,小明列出了顧客最喜歡的n種花,從1到n標號。為了在門口展出更多種花,規定第i種花不能超過ai盆,擺花時同一種花放在一起,且不同種類的花需按標號的從小到大的順序依次擺列。試程式設計計算,一共有多少種不同的擺花方案。...
洛谷 P1077 擺花
題目原位址 2 4 3 2 輸出 2首先,我們想到的一定是暴力dfs 20分 include include using namespace std int n,m,ans,a 105 b 105 void dfs int k,int space if k n return for int i mi...
洛谷 P1077 擺花
一道簡單的dp問題。dp i j 表示前i種花j個花盆的方案數。那麼就有狀態轉移方程為sum dp i 1 k 其中k的取值是從0到min j,a i include using namespace std int m,n int dp 105 105 int a 105 int mod 10000...