Facebook Hacker Cup 2017 Round 1 Pie Progress

Facebook Hacker Cup 2017 Round 1

Some pies are sweet, full of fruit and jam and sugar.

Some pies are savory, full of meat and potatoes and spices.

Some pies are in fact not pies at all but tarts or galettes. This probably won't stop you from eating them.

Every single day for N days, you're determined to eat a pie for dinner. Every morning, you'll take a trip to your local pie shop, and buy 0 or more of their pies. Every night, you'll eat one pie that you've bought. Pies never go bad, so you don't need to eat a pie on the same day that you bought it. You may instead eat one that you purchased on an earlier day.

On the ith day, the shop has M pies for sale, with the jth of these pies costing Ci,j dollars. You can choose to buy any (possibly empty) subset of them. However, this shop has measures in place to protect itself against crazy pie fanatics buying out its products too quickly. In particular, if you buy p pies on a single day, you must pay an additional tax of p2 dollars.

Input

Input begins with an integer T, the number of times you go on a pie-eating spree. For each case, there is first a line containing two space-separated integers, N and M. Then, N lines follow, each containing M space-separated integers. The jth integer on the ith line is Ci,j.

Output

For the ith case, print a line containing "Case #i: " followed by the minimum you need to pay to eat a pie every day.

Constraints

1 ≤ T ≤ 100 
1 ≤ NM ≤ 300 
1 ≤ Ci,j ≤ 1,000,000 

Explanation of Sample

In the first case, you should buy both pies on the first day, for a total cost of 1 + 1 + 22 = 6. On the second day you should buy one pie for 100 + 12 = 101. On the third day you can eat one of the spare pies you bought on the first day.

In the third case, you should buy and eat the cheapest pie every day, for a daily cost of 1 + 12 = 2, and a total cost of 10.

In the fourth case, one possible solution is to buy two pies on the first day (1 + 1 + 22 = 6), two pies on the second day (2 + 2 + 22 = 8), and one pie on the third day (3 + 12 = 4) for a total cost of 18. On the fourth and fifth days you can eat your two spare pies from the first and second days.

题意:一家买馅饼的店,第i 天,种类为j 的馅饼售价Ci,j元,问要想每天都有一个馅饼吃,最少要花多少钱。馅饼可以永久存放不会坏,所以可以提前买很多,同时每天买p个馅饼需要交税p*p。

思路:动态规划,状态定义 dp[i][j]  代表前i天,买j个馅饼所要花费的最少金钱数。即dp[n][n]就是最终的答案了。

转移方程的思路:

1.对于第一天,当然可以选择买1~m个,要使得价钱最低,把价钱从小到大排序即可满足。

2.不是第一天的情况,当前天枚举买的馅饼数目j,同时枚举j里面有k个馅饼是当前天买的,j-k个是前面提前买的。

dp[i][j] = min(dp[i][j], dp[i-1][j - k] + k^2 + k个馅饼的最小价钱)


#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <math.h>
#define INF 0x3f3f3f3f
const int N = 310;
using namespace std;
int rec[N][N];
int dp[N][N];
int sum[N][N];
void run()
{
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++)
  {
    for (int j = 1; j <= m; j++)
      scanf("%d", rec[i] + j);
    sort(rec[i] + 1, rec[i] + 1 + m);
  }
 
  memset(dp, INF, sizeof(dp));
  memset(sum, 0, sizeof(sum));

  dp[1][1] = rec[1][1] + 1;
  sum[1][1] = rec[1][1];
  for (int i = 2; i <= m; i++)
  {
    sum[1][i] = sum[1][i-1] + rec[1][i];
    dp[1][i] = sum[1][i] + i*i;
  }
  //看了别人的代码并没有开sum数组,仔细分析一下
  //sum数组其实是不必开的,因为使用时每种求和也
  //是只用了一次,用时用一个变量存储之前计算的结果就好了
  //不必多开个数组
  for (int i = 2; i <= n; i++)
  {
    sum[i][1] = rec[i][1];
    for (int j = 2; j <= m; j++)
      sum[i][j] = sum[i][j-1] + rec[i][j];
  }
 
  for (int i = 2; i <= n; i++)
    for (int j = i; j <= n; j++)
       for (int k = 0; k <= j && k <= m; k++)//最多m个馅饼,所以当前k最多是m,j-k要大于等于0
        {                                    //所以k要小于等于j
          dp[i][j] = min(dp[i][j], dp[i-1][j - k] + k*k + sum[i][k]);         
        }
  printf("%d\n", dp[n][n]);
}
int main()
{
#ifndef ONLINE_JUDGE  
    freopen("in.txt","r" ,stdin);
#endif 
    freopen("out.txt","w",stdout);
    int T, cas = 1;
    
    scanf("%d", &T);
    while (T--)
    {
      printf("Case #%d: ", cas++);
      run();
    }
    return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值