文章来源
小明喜欢玩拼板游戏,买了 N N N块正方形的拼板,边长分别是 A 1 , A 2 , . . . A N A_1,A_2,...A_N A1,A2,...AN。可是在玩拼图游戏的过程中,他发现自己把拼板的尺寸搞错了。所以他需要调换其中的一些,使得调换以后所有拼板总面积正好是 M M M。调换拼板是需要成本的,把一块边长是 A i A_i Ai的拼板替换成一块边长是 B i B_i Bi的拼板需要的成本是 ( A i − B i ) 2 (A_i-B_i)^2 (Ai−Bi)2。特别的,小明只能把之前买的拼板用来做调换。也就是说,他不能用 A A A拼板来调换 B B B拼板,然后再用 B B B拼板来调换 C C C拼板。
请你计算,小明要达到目的所需要花的最小代价。如果无法达到目的,输出 − 1 -1 −1。
第 1 1 1行,两个空格分开的整数, N N N和 M M M。
第 2 2 2到 N + 1 N+1 N+1行,每行一个整数 A i A_i Ai。
一个整数,能通过调换使得总面积达到 M M M的最小代价,如果不可行输出 − 1 -1 −1。
输入:
3 6
3
3
1
输出:
5
样例说明:一共有 3 3 3块拼板,两块的边长为 3 3 3,一块的边长为 1 1 1,想要通过替换使得总面积为 6 6 6。
把两块边长为 3 3 3的拼板分别调换为边长为 2 2 2和边长为 1 1 1的,总面积变成 4 + 1 + 1 = 6 4+1+1=6 4+1+1=6,所需要花的代价是 4 + 1 = 5 4+1=5 4+1=5。
1 ≤ N ≤ 10 1≤N≤10 1≤N≤10
1 ≤ M ≤ 10000 1≤M≤10000 1≤M≤10000
1 ≤ A i ≤ 100 1≤A_i≤100 1≤Ai≤100
发现 M M M的范围非常小。
于是乎想到dp。
d p [ i ] [ j ] dp[i][j] dp[i][j]表示只用前 j j j块拼板获得 i i i面积所需要的最小代价, I N F INF INF表示不可行。转移方程为:
d p [ i ] [ j ] = min { ( k − A [ j ] ) 2 + d p [ i − k ∗ k ] [ j − 1 ] } dp[i][j] = \min\{(k-A[j])^2 + dp[i-k*k][j-1]\} dp[i][j]=min{(k−A[j])2+dp[i−k∗k][j−1]}(只考虑换第j块平板)
初始条件: d p [ 0 ] [ 0 ] = 0 , d p [ i > 0 ] [ 0 ] = I N F dp[0][0]=0,dp[i>0][0]=INF dp[0][0]=0,dp[i>0][0]=INF
时间复杂度: O ( N M M ) = 1 0 7 O(NM\sqrt{M})=10^7 O(NMM)=107
代码:
#include
using namespace std;
#define INF 1919810114
int n,m;
int a[20];
int dp[10010][20];
int main(){
freopen("slab.in","r",stdin);
freopen("slab.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) dp[i][0]=INF;
for(int j=1;j<=n;j++)
for(int i=0;i<=m;i++){
dp[i][j]=INF;
for(int k=1;k*k<=i;k++) dp[i][j]=min(dp[i][j],(a[j]-k)*(a[j]-k)+dp[i-k*k][j-1]);
}
if(dp[m][n]==INF) cout<<-1;
else cout<<dp[m][n];
return 0;
}