动态规划问题,一开始看到每天要买的糖果数还不一样,而且每个糖果还有他自己不同的价格。直接就想到了状压DP。
但本题要求花费最小,而对于某一天买k个糖果来说花费最小其实就是从价格低的糖果来买就行了。那么某一天如何选糖果的问题就这样简答的解决了。
那么状态数组为:dp[i][j]。i代表天数,j代表第到i天一共买j个糖果。值代表花费。
状态转移方程为:dp[i][j] = d[i-1][j-k]+cost(i, k)+pow(k,2);。
表示到某天一共买了j个糖果,取决于这天买了k个糖果,那么上一天就需要一共买了i-k个糖果。cost是计算这天买了k个糖果的最小花费是多少,pow(k,2)。是多余的花费。
//dp[i][j]。i代表天数,j代表第到i天一共买j个糖果。值代表花费
//状态转移方程:dp[i][j] = d[i-1][j-k]+cost(i, k)+pow(k,2);
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 300+10;
int dp[maxn][maxn];
int price[maxn][maxn];

int cost(int day, int num)
{
    int cnt = 0;
    for (int i=1;i<=num;i++)
    {
        cnt += price[day][i];
    }
    return cnt;
}

signed main()
{
    memset(dp, 127, sizeof dp);
    int n, m;
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            cin>>price[i][j];
        }
    }
    for (int i=1;i<=n;i++) sort(price[i]+1, price[i]+m+1);
    dp[0][0] = 0;
    for (int i=1;i<=n;i++)
    {
        for (int j=i;j<=n;j++)
        {
            if ((i)*m<j) continue;
            for (int k=0;k<=j;k++)
            {
                dp[i][j] = min(dp[i][j], dp[i-1][j-k]+cost(i,k)+k*k);
//                 cout<<"i="<<i<<" j="<<j<<endl;
//                 cout<<"dp[i][j]="<<dp[i][j]<<endl;
            }
        }
    }
    cout<<dp[n][n];
    return 0;
}