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; 
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章