☆【動的計画】木馬級デーモンプロセス


【    】 
  “   ,    ,       ,    。”     。 
                    ,                   
  。      ,                              
        。 
                 ,       ,              
     (      ),      k        ,           。  
           ,  n   m  。            ,        
           ,             。             ,
                k                  。 
 
【    】 
        n,m,k。 
    n     m   ,           。 
 
【    】 
    ,         。 
 
【    】 
4 2 2 
-4 -1 
22 18 
-1 -4 
30 10 
 
【    】 
80 
 
【       】 
   40%     :m=1; 
   100%   :1≤n≤100,1≤m≤2,1≤k≤10。 
k           ,       。 
         longint   。

これはダイナミックな計画問題です.まずm=1の場合を考える.状態:前i行でシャットダウンj回で得られる最大価値をf[i][j]で表す.遷移方程式:f[i][j]=max{f[i-1][j],f[k][j-1]+sum[i]-sum[k]}が容易に得られる.ここで、sum[i]は、この列iの接頭辞和を表す.m=2の場合を再考する.ステータス:同上.f値を計算する前にf 0[L][R][j]とf 1[L][R][j]を前処理し、それぞれ1,2列目(L,R)という区間関j回の最大収益を表す.それでは、ステップごとの決定には4種類ある:1)選択しない;2)第一列のサブ矩形を選択する.3)第二列のサブ矩形を選択する.4)第1列および第2列のサブ長方形を選択します.得られる移行方程式:
f[i][j] = max{f[i - 1][j], f[k][j - 1] + sum1[i] - sum1[k] + sum2[i] - sum2[k], f[k][j - u - v] + f0[k][i][u] + f1[k][i][v]}.
ここでsum 1[i]およびsum 2[i]は、それぞれ第1列および第2列iのプレフィックス和を表す.
Accode:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>

const char fi[] = "mua.in";
const char fo[] = "mua.out";
const int maxN = 110;
const int maxK = 20;
const int MAX = 0x3fffff00;
const int MIN = -MAX;

int c[maxN][2];
int sum[maxN][2];
int f[maxN][maxK];
int f0[maxN][maxN][maxK];
int f1[maxN][maxN][maxK];
int n, m, K, ans;

  void init_file()
  {
    freopen(fi, "r", stdin);
    freopen(fo, "w", stdout);
  }

  void readdata()
  {
    scanf("%d%d%d", &n, &m, &K);
    for (int i = 1; i < n + 1; ++i)
     for (int j = 0; j < m; ++j)
      {
        int x;
        scanf("%d", &x);
        sum[i][j] = sum[i - 1][j] + x;
      }
  }

  void work1()
  {
    memset(f, 0x80, sizeof(f));
    for (int j = 0; j < K + 1; ++j) f[0][j] = 0;
    for (int i = 1; i < n + 1; ++i)
     for (int j = 0; j <= K && j <= i; ++j)
      {
        f[i][j] = f[i - 1][j];
        if (j) for (int k = 1; k < i + 1; ++k)
          f[i][j] = std::max(f[i][j],
            f[k][j - 1] + sum[i][0] - sum[k][0]);
        ans = std::max(ans, f[i][j]);
      }
  }

  void work2()
  {
    memset(f0, 0x80, sizeof(f0));
    memset(f1, 0x80, sizeof(f1));
    memset(f, 0x80, sizeof(f));
    for (int L = 0; L < n; ++L)
    {
      for (int j = 0; j < K + 1; ++j)
        f0[L][L][j] = f1[L][L][j] = 0;
      for (int R = L + 1; R < n + 1; ++R)
       for (int j = 0; j <= K; ++j)
        {
          f0[L][R][j] = f0[L][R - 1][j];
          f1[L][R][j] = f1[L][R - 1][j];
          if (j) for (int k = L; k < R + 1; ++k)
          {
            f0[L][R][j] = std::max(f0[L][R][j],
              f0[L][k][j - 1] +
              sum[R][0] - sum[k][0]);
            f1[L][R][j] = std::max(f1[L][R][j],
              f1[L][k][j - 1] +
              sum[R][1] - sum[k][1]);
          }
        }
    }
    for (int j = 0; j < K + 1; ++j) f[0][j] = 0;
    for (int i = 1; i < n + 1; ++i)
     for (int j = 0; j <= K && j <= i; ++j)
      {
        f[i][j] = f[i - 1][j];
        if (j)
        {
          for (int k = 1; k < i + 1; ++k)
            f[i][j] = std::max(f[i][j],
              f[k][j - 1] + sum[i][0] - sum[k][0]
              + sum[i][1] - sum[k][1]);
          for (int k = 1; k < i; ++k)
           for (int u = 0; u <= j; ++u)
            for (int v = 0; u + v <= j; ++v)
              f[i][j] = std::max(f[i][j],
                f[k][j - u - v] + f0[k][i][u]
                + f1[k][i][v]);
        }
        ans = std::max(ans, f[i][j]);
      }
  }

  void print() {printf("%d", ans); }

int main()
{
  init_file();
  readdata();
  if (m == 1) work1(); else work2();
  print();
  exit(0);
}

2回目:
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <string>
#define max(a, b) ((a) > (b) ? (a) : (b))

const char fi[] = "mua.in", fo[] = "mua.out";
const int maxN = 110, maxK = 20;
const int MAX = 0x3f3f3f3f, MIN = ~MAX;

int f[maxK][maxN][maxN], f1[maxK][maxN];
int sum[maxN][2];
int n, m, K;

void init_file()
{
    freopen(fi, "r", stdin);
    freopen(fo, "w", stdout);
    return;
}

inline int getint()
{
    int res = 0; char tmp; bool sgn = 1;
    do tmp = getchar();
    while (!isdigit(tmp) && tmp != '-');
    if (tmp == '-') {sgn = 0; tmp =getchar();}
    do res = (res << 3) + (res << 1) + tmp - '0';
    while (isdigit(tmp = getchar()));
    return sgn ? res : -res;
}

void readdata()
{
    n = getint(); m = getint(); K = getint();
    for (int i = 1; i < n + 1; ++i)
    for (int j = 0; j < m; ++j)
        (sum[i][j] = getint()) += sum[i - 1][j];
    return;
}

int work1()
{
    for (int k = 1; k < K + 1; ++k)
    for (int i = 1; i < n + 1; ++i)
    {
        f1[k][i] = f1[k][i - 1];
        for (int j = 0; j < i; ++j)
            f1[k][i] = max(f1[k][i], f1[k - 1][j]
                           + sum[i][0] - sum[j][0]);
    }
    return f1[K][n];
}

int work2()
{
    for (int k = 1; k < K + 1; ++k)
    for (int i = 0; i < n + 1; ++i)
    for (int j = 0; j < n + 1; ++j)
    if (i || j)
    {
        if (i == j)
        {
            f[k][i][j] = max(f[k][i][j - 1], f[k][i - 1][j]);
            for (int t = 0; t < i; ++t)
                f[k][i][j] = max(f[k][i][j], f[k - 1][t][t]
                                 + sum[i][0] - sum[t][0]
                                 + sum[i][1] - sum[t][1]);
        }
        else if (i > j)
        {
            f[k][i][j] = f[k][i - 1][j];
            for (int t = 0; t < i; ++t)
                f[k][i][j] = max(f[k][i][j], f[k - 1][t][j]
                                 + sum[i][0] - sum[t][0]);
        }
        else if (i < j)
        {
            f[k][i][j] = f[k][i][j - 1];
            for (int t = 0; t < j; ++t)
                f[k][i][j] = max(f[k][i][j], f[k - 1][i][t]
                                 + sum[j][1] - sum[t][1]);
        }
    }
    return f[K][n][n];
}

int main()
{
    init_file();
    readdata();
    printf("%d
", (m == 1) ? work1() : work2()); return 0; }