题意: 有一个n*m(1<= n,m<=30)的矩形巧克力,每次能横向或者是纵向切,且每次切的花费为所切边长的平方,问你最后得到k个单位巧克力( k <= min(n*m,50) )的最小花费是多少?
思路: 数据规模不大,但是贪心不能得到最优解,很自然想到了dp;里面涉及到行的减少和列的减少,在dp[][]表示中必定要以行数和列数作为dp的含义,但是好像这还不够,如果单单只是一个二维的dp[][]那这个表示的是取了(或者还需)几个单位巧克力呢?
==>三维dp[n][m][k]:当还剩下n行m列还需要取k个单位巧克力时的最小花费;
转移式就是对每个”可切”的行||列遍历,取最小的花费;注意将n,m分开后,还要对之后各自所要得到的巧克力的数量进行划分,即对k进行遍历(从0开始);即dp数组作为记忆,否则直接dfs会TLE.
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i = 0;i < (n);i++) #define inf 0x3f3f3f3f int dp[33][33][55]; int dfs(int n,int m,int k) { if(k <= 0||n * m == k)return 0; int &ret = dp[n][m][k]; if(ret) return ret; else ret = inf; for(int i = 1;i < n;i++){ for(int j = 0;j <= k;j++) ret = min(ret, dfs(i,m,j) + dfs(n-i,m,k - j) + m*m); } for(int i = 1;i < m;i++){ for(int j = 0;j <= k;j++) ret = min(ret, dfs(n,i,j) + dfs(n,m-i,k - j) + n*n); } return ret; } int main() { int T,n,m,k; cin>>T; while(T--){ scanf("%d%d%d",&n,&m,&k); printf("%d ",dfs(n,m,k)); } }