【Educational Codeforces Round 1E】【动态规划-多维DP】Chocolate Bar 矩形巧克力掰开吃的最小成本
2015-11-19 12:58
573 查看
E. Chocolate Bar
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You have a rectangular chocolate bar consisting of n × m single
squares. You want to eat exactly k squares,
so you may need to break the chocolate bar.
In one move you can break any single rectangular piece of chocolate in two rectangular pieces. You can break only by lines between squares: horizontally or vertically. The cost of
breaking is equal to square of the break length.
For example, if you have a chocolate bar consisting of 2 × 3 unit
squares then you can break it horizontally and get two 1 × 3 pieces (the cost of such breaking is 32 = 9),
or you can break it vertically in two ways and get two pieces: 2 × 1 and 2 × 2 (the
cost of such breaking is 22 = 4).
For several given values n, m and k find
the minimum total cost of breaking. You can eat exactly k squares of chocolate
if after all operations of breaking there is a set of rectangular pieces of chocolate with the total size equal to k squares.
The remaining n·m - ksquares
are not necessarily form a single rectangular piece.
Input
The first line of the input contains a single integer t (1 ≤ t ≤ 40910) —
the number of values n, m and k to
process.
Each of the next t lines
contains three integers n, m and k (1 ≤ n, m ≤ 30, 1 ≤ k ≤ min(n·m, 50)) —
the dimensions of the chocolate bar and the number of squares you want to eat respectively.
Output
For each n, m and k print
the minimum total cost needed to break the chocolate bar, in order to make it possible to eat exactly ksquares.
Sample test(s)
input
output
Note
In the first query of the sample one needs to perform two breaks:
to split 2 × 2 bar into two pieces of 2 × 1 (cost
is 22 = 4),
to split the resulting 2 × 1 into two 1 × 1 pieces
(cost is 12 = 1).
In the second query of the sample one wants to eat 3 unit
squares. One can use exactly the same strategy as in the first query of the sample.
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=0,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int f[32][32][52];
void DP()
{
//初始化
MS(f,63);
for(int i=0;i<=30;i++)
{
for(int j=0;j<=30;j++)f[i][j][0]=0;
}
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)if(i*j<=50)f[i][j][i*j]=0;
}
//状态转移
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)
{
int top=min(i*j,50);
for(int k=1;k<=top;k++)//总共要切的份数
{
for(int u=1;u<=i/2;u++)//横着切
{
int topp=min(u*j,k);
for(int kk=0;kk<=topp;kk++)
{
gmin(f[i][j][k],f[u][j][kk]+f[i-u][j][k-kk]+j*j);
}
}
for(int v=1;v<=j/2;v++)//竖着切
{
int topp=min(v*i,k);
for(int kk=0;kk<=topp;kk++)
{
gmin(f[i][j][k],f[i][v][kk]+f[i][j-v][k-kk]+i*i);
}
}
}
}
}
}
int main()
{
DP();int n,m,k;
scanf("%d",&casenum);
for(casei=1;casei<=casenum;casei++)
{
scanf("%d%d%d",&n,&m,&k);
printf("%d\n",f
[m][k]);
}
return 0;
}
/*
【trick&&吐槽】
1,不要让自己太懒惰呀,这道水题就是差1分钟AC >_<
2,没有AC的原因是我把数组给爆了!初始化的边界问题也要多多注意呀!RE时返回的可能并不是RE
【题意】
有T(4e4)组询问。
对于每组询问,问你,我们想要在一个n(30)*m(30)的大巧克力中,
吃掉一个大小为k(1<=k<=min(n*m,50))的小巧克力的最小体力成本。
吃巧克力为什么需要体力成本呢?
因为如果巧克力太大了,我们就要把它掰开。
对于一个i*j的巧克力,我们可以横着沿[1,i-1]的线掰开,也可以纵着沿[1,j-1]的线掰开。
横着掰开的成本是掰开巧克力的宽度,也就是j;纵着掰开的成本是掰开巧克力的长度,也就是i。
【类型】
DP
【分析】
我们直接枚举
1,大巧克力的长
2,大巧克力的宽
3,吃巧克力的大小
4,横着还是竖着切,在哪里切
5,一侧吃的巧克力的大小
6,另一侧吃的巧克力的大小
这道题就做完啦
时间复杂度为O(n*m*k*(n+m)*k)
大概为30*30*50*60*50=1.35e8
AC完全没有压力!这样就AC啦!
具体来说——
就是定义f[i][j][k]表示我们在一个i*j的巧克力块中吃一个大小恰好为k的巧克力的成本
数组大小为[31][31][51]
初始化f[i][j][0]=f[i][j][i*j] 注意i*j可能达到900,然而我们数组才开到50,于是这里要特判下。
做CF的时候我就是因为这里的错误没有做到AC >_<
状态转移方程为——
gamx(f[i][j][k],f[u][j][kk]+f[i-u][j][k-kk]+j*j);u∈[1,j/2],u表示横着切的位置,我们只需要枚举小的那一半即可,成本自然是j*j
gamx(f[i][j][k],f[i][v][kk]+f[i][j-v][k-kk]+i*i);v∈[1,i/2],v表示竖着切的位置,我们只需要枚举小的的一半即可,成本自然是i*i
kk表示在这一半吃的巧克力的数量,显然kk∈[0,min(u*j,k)]或kk∈[0,min(i*v,k)];
这样更新一下,我们永远是先更新小的矩阵,再更新大的矩形。后效性一定有保证。每个状态都得到了更新。
于是最后直接输出f
[m][k]即可。
【时间复杂度&&优化】
O(n*m*k*(n+m)*k)
【数据】
10 10 9
*/
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You have a rectangular chocolate bar consisting of n × m single
squares. You want to eat exactly k squares,
so you may need to break the chocolate bar.
In one move you can break any single rectangular piece of chocolate in two rectangular pieces. You can break only by lines between squares: horizontally or vertically. The cost of
breaking is equal to square of the break length.
For example, if you have a chocolate bar consisting of 2 × 3 unit
squares then you can break it horizontally and get two 1 × 3 pieces (the cost of such breaking is 32 = 9),
or you can break it vertically in two ways and get two pieces: 2 × 1 and 2 × 2 (the
cost of such breaking is 22 = 4).
For several given values n, m and k find
the minimum total cost of breaking. You can eat exactly k squares of chocolate
if after all operations of breaking there is a set of rectangular pieces of chocolate with the total size equal to k squares.
The remaining n·m - ksquares
are not necessarily form a single rectangular piece.
Input
The first line of the input contains a single integer t (1 ≤ t ≤ 40910) —
the number of values n, m and k to
process.
Each of the next t lines
contains three integers n, m and k (1 ≤ n, m ≤ 30, 1 ≤ k ≤ min(n·m, 50)) —
the dimensions of the chocolate bar and the number of squares you want to eat respectively.
Output
For each n, m and k print
the minimum total cost needed to break the chocolate bar, in order to make it possible to eat exactly ksquares.
Sample test(s)
input
4 2 2 1 2 2 3 2 2 2 2 2 4
output
5 5 4 0
Note
In the first query of the sample one needs to perform two breaks:
to split 2 × 2 bar into two pieces of 2 × 1 (cost
is 22 = 4),
to split the resulting 2 × 1 into two 1 × 1 pieces
(cost is 12 = 1).
In the second query of the sample one wants to eat 3 unit
squares. One can use exactly the same strategy as in the first query of the sample.
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=0,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int f[32][32][52];
void DP()
{
//初始化
MS(f,63);
for(int i=0;i<=30;i++)
{
for(int j=0;j<=30;j++)f[i][j][0]=0;
}
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)if(i*j<=50)f[i][j][i*j]=0;
}
//状态转移
for(int i=1;i<=30;i++)
{
for(int j=1;j<=30;j++)
{
int top=min(i*j,50);
for(int k=1;k<=top;k++)//总共要切的份数
{
for(int u=1;u<=i/2;u++)//横着切
{
int topp=min(u*j,k);
for(int kk=0;kk<=topp;kk++)
{
gmin(f[i][j][k],f[u][j][kk]+f[i-u][j][k-kk]+j*j);
}
}
for(int v=1;v<=j/2;v++)//竖着切
{
int topp=min(v*i,k);
for(int kk=0;kk<=topp;kk++)
{
gmin(f[i][j][k],f[i][v][kk]+f[i][j-v][k-kk]+i*i);
}
}
}
}
}
}
int main()
{
DP();int n,m,k;
scanf("%d",&casenum);
for(casei=1;casei<=casenum;casei++)
{
scanf("%d%d%d",&n,&m,&k);
printf("%d\n",f
[m][k]);
}
return 0;
}
/*
【trick&&吐槽】
1,不要让自己太懒惰呀,这道水题就是差1分钟AC >_<
2,没有AC的原因是我把数组给爆了!初始化的边界问题也要多多注意呀!RE时返回的可能并不是RE
【题意】
有T(4e4)组询问。
对于每组询问,问你,我们想要在一个n(30)*m(30)的大巧克力中,
吃掉一个大小为k(1<=k<=min(n*m,50))的小巧克力的最小体力成本。
吃巧克力为什么需要体力成本呢?
因为如果巧克力太大了,我们就要把它掰开。
对于一个i*j的巧克力,我们可以横着沿[1,i-1]的线掰开,也可以纵着沿[1,j-1]的线掰开。
横着掰开的成本是掰开巧克力的宽度,也就是j;纵着掰开的成本是掰开巧克力的长度,也就是i。
【类型】
DP
【分析】
我们直接枚举
1,大巧克力的长
2,大巧克力的宽
3,吃巧克力的大小
4,横着还是竖着切,在哪里切
5,一侧吃的巧克力的大小
6,另一侧吃的巧克力的大小
这道题就做完啦
时间复杂度为O(n*m*k*(n+m)*k)
大概为30*30*50*60*50=1.35e8
AC完全没有压力!这样就AC啦!
具体来说——
就是定义f[i][j][k]表示我们在一个i*j的巧克力块中吃一个大小恰好为k的巧克力的成本
数组大小为[31][31][51]
初始化f[i][j][0]=f[i][j][i*j] 注意i*j可能达到900,然而我们数组才开到50,于是这里要特判下。
做CF的时候我就是因为这里的错误没有做到AC >_<
状态转移方程为——
gamx(f[i][j][k],f[u][j][kk]+f[i-u][j][k-kk]+j*j);u∈[1,j/2],u表示横着切的位置,我们只需要枚举小的那一半即可,成本自然是j*j
gamx(f[i][j][k],f[i][v][kk]+f[i][j-v][k-kk]+i*i);v∈[1,i/2],v表示竖着切的位置,我们只需要枚举小的的一半即可,成本自然是i*i
kk表示在这一半吃的巧克力的数量,显然kk∈[0,min(u*j,k)]或kk∈[0,min(i*v,k)];
这样更新一下,我们永远是先更新小的矩阵,再更新大的矩形。后效性一定有保证。每个状态都得到了更新。
于是最后直接输出f
[m][k]即可。
【时间复杂度&&优化】
O(n*m*k*(n+m)*k)
【数据】
10 10 9
*/
相关文章推荐
- 【Educational Codeforces Round 1A】【水题】Tricky Sum 1~n之和减去2的幂
- 【Educational Codeforces Round 1B】【字符串平移 水题】Queries on a String 字符串平移水题
- 【Educational Codeforces Round 1C】【计算几何-极角排序 atan2 long double】Nearest vectors 平面图上原点引出角度最小的两个
- 【Educational Codeforces Round 1D】【DFS 联通块打标记法】Igor In the Museum 联通块内墙的面数
- 【Codeforces Round 169 (Div 2) E】【数据结构区间维护】Little Girl and Problem on Trees 大菊花树的距离性修改查询
- 【hihocoder [Offer收割]编程练习赛9 D】【简单DP】矩阵填数
- 【HDU5951 2016ACM ICPC亚洲区沈阳站-重现赛 D】【博弈 DP】Recursive sequence n物品A元B元连续竞价的平衡点
- 【HDU5932 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 K】【树上背包 贪心乱搞】Backpack on Tree 物品成本只有12345下的树上背包
- 【Codeforces Round 375 (Div 2) F】【构造 贪心】st-Spanning Tree 树的特殊最小生成树使得S度不超SD,T度不超TD
- 【Codeforces Round 375 (Div 2) E】【欧拉回路Fleury算法 或网络流】One-Way Reform 每条边定向使得最多的点满足入度=出度
- 【Codeforces Round 375 (Div 2) D】【简单dfs】Lakes in Berland
- 【Codeforces Round 375 (Div 2) C】【语文题】Polycarp at the Radio
- 【Codeforces Round 375 (Div 2) B】【水模拟】Text Document Analysis
- 【Codeforces Round 375 (Div 2) A】【水题】The New Year Meeting Friends
- 【Intel Code Challenge Elimination Round (Div1 + Div2, combined) D】【贪心 暴力 SET】Generating Sets n个不同的x变
- 【Intel Code Challenge Elimination Round (Div1 + Div2, combined) C】【正难则反并查集】n数按照次序删除每次删除后最大联通块之和
- 【Intel Code Challenge Elimination Round (Div1 + Div2, combined) B】【水题】Verse Pattern
- 【Intel Code Challenge Elimination Round (Div1 + Div2, combined) A】【暴力or讨论】Broken Clock 把给定时间修改到目标时间制
- 【Codeforces Round 374 (Div 2)D】【贪心】 Maxim and Array n个数做K次±X使得乘积尽可能小
- 【HDU5896 2016 ACM ICPC Asia Regional Shenyang Online E】【DP 排列组合 分治ntt】Running King n个点构成含环无向图的方案数.cp