POJ 1042 Gone Fishing (DP)

来源:互联网 发布:制作ubuntu u盘启动盘 编辑:程序博客网 时间:2024/06/05 07:49

解题思路 (DP)

假如在给定时间h内,最远到达第个i湖时,最多捕鱼数为F(i, h), 那么问题的解为 

MAX{F(i, h)}, i=1...n

考虑最远到达第i个湖时,除去路途中的时间,最多的有效捕鱼时间为 hi = h - sum(t[0]+...+t[i-1]), 那么:
F(i, h) <=> maxfish(i, hi) 
且有
MAX{F(i, h)} = MAX{maxfish(i, hi)} = MAX{maxfish(1,h1), ..., maxfish(n,hn)}

这里maxfish(i, k)表述为原问题的简化形式:
不考虑湖之间的消耗时间(即t0=t1=...=t[i-1]=0),给定时间k内,在i个湖的最多捕鱼数。

建立递推关系,maxfish(i, k)取下列最大者:
{ k时间内在i-1个湖的最多捕鱼数; k时间内在第i个湖捕鱼时间大于0的所有情况的最多捕鱼数 }

maxfish(i, k) = MAX{ maxfish(i-1,k), lakefish(i,j)+maxfish(i-1,k-j) }, 1<j<=k 
lakefish(i,j)表示在第i个湖捕鱼j时间能捕到的总鱼数。

原问题MAX{maxfish(i, hi)},只需构造maxfish(n,hn)的解,maxfish(1,h1),...,maxfish(n-1,h[n-1])为过程中更小规模的子问题的解,这n个不同规模的子问题的解的最大者,即为原问题的解。

这个思路的关键在于,将问题简化为不考虑湖之间花费的时间,能更容易使用动态规划来求解。
注意点:
1. 计算过程中h时间转化为单位时间h=h*12, 求解完后输出时间均*5

2. 剩余时间放到第一个湖

代码

#include <iostream>#include <memory.h>using namespace std;int f[26];int d[26];int t[25];int lakefish[26][193];int maxfish[26][193];  int spent[26][193];  int spentMax[26];int main(int argc, char** argv){  int cases = 0;  int n, h;  while (cin >> n)  {    if (n > 0 && cases > 0)    {      cout << endl;    }    if (n == 0) { break; }    ++ cases;    // input    cin >> h;    h = h * 12;    for (int i = 1; i <= n; ++i)    {      cin >> f[i];    }    for (int i = 1; i <= n; ++i)    {      cin >> d[i];    }    for (int i = 1; i < n; ++i)    {      cin >> t[i];    }    // lakefish(i,j)    memset(lakefish, 0, sizeof(lakefish));    int fk = 0;    for (int i = 1; i <= n; ++i)    {      for (int k = 1; k <= h; ++k)      {          fk = f[i] - d[i] * (k - 1);          if (fk > 0)          {            lakefish[i][k] = lakefish[i][k-1] + fk;          }          else          {            lakefish[i][k] = lakefish[i][k-1];          }      }    }    // 1. maxfish(i, k) = MAX{ maxfish(i-1,k), lakefish(i,j)+maxfish(i-1,k-j)}, 1<j<=k     // 2. result = MAX{maxfish(1,h1), ..., maxfish(n,hn)}    memset(maxfish, 0, sizeof(maxfish));    memset(spent, 0, sizeof(spent));    memset(spentMax, 0, sizeof(spentMax));    int hi = h;    int fishij = -1;    int maxfishnk = -1, maxfishn = -1, maxfishh = -1;    for (int i = 1; i <= n; ++i)    {        hi = hi - t[i-1];         for (int k = 1; k <= hi; ++k)        {            maxfish[i][k] = maxfish[i-1][k];            spent[i][k] = 0;            for (int j = 1; j <= k; ++j)            {               fishij = lakefish[i][j] + maxfish[i-1][k-j];               if (fishij > maxfish[i][k])               {                  maxfish[i][k] = fishij;                  spent[i][k] = j;               }            }            if (k == hi && maxfish[i][k] > maxfishnk)            {              maxfishnk = maxfish[i][k];              maxfishn = i;              maxfishh = k;            }        }    }    // output    int i = maxfishn;    int k = maxfishh;    while (i > 0)    {      spentMax[i] = spent[i][k];      k = k - spentMax[i];      if (i == 1) { spentMax[i] += k; }      -- i;    }    for (int i = 1; i <= n; ++i)    {      if (i > 1) { cout << ", "; }      cout << spentMax[i]*5;    }    cout << endl << "Number of fish expected: " << maxfishnk <<endl;  }  return 0;}


0 0