UVa1628

通过读题,我们发现这道题与修筑长城非常的像,而修筑长城顺手修了一定更好,但是这道题中顺手将pizza送出并不能更好,可能会

“倒贴”,所以不能完全的像修筑长城那样解决问题,那么这道题怎么办呢?

又从读题中我们发现数据范围十分的小,并且单位时间内每个客户的费用相同,这就告诉我们可以增加状态的维度或者决策数来更加

贴近这道题,由于我们无法确定那个客户送pizza,那个客户不管,所以状态上必须有所体现。

我们设d(i,j,k,p)表示[i,j]区间不管(可能这个区间送出了pizza也可能没有)还要给k个用户送出pizza的最大收益,其中p为0时说明在i处,

p为1时说明在j处,状态转移方程看程序就行了,其中时间的求法非常巧妙,下面是代码:

// UVa 1628
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std; 

const int maxn = 100 + 5; 

int n, pos[maxn], v[maxn], kase;  
int d[maxn][maxn][maxn][2], vis[maxn][maxn][maxn][2]; 

int dp(int s, int e, int k, int p) {
  if (k == 0) return 0; 
  
  int& ans = d[s][e][k][p];
  if (vis[s][e][k][p] == kase) return ans; 
  vis[s][e][k][p] = kase;     
  
  ans = 0; 
  if (!p) {
    for (int i = 0; i < s; ++i) 
      ans = max(ans, v[i]-k*abs(pos[i]-pos[s])+dp(i,e,k-1,0));
    for (int i = e+1; i < n; ++i)    
      ans = max(ans, v[i]-k*abs(pos[i]-pos[s])+dp(s,i,k-1,1)); 
  } 
  else {
    for (int i = 0; i < s; ++i) 
      ans = max(ans, v[i]-k*abs(pos[i]-pos[e])+dp(i,e,k-1,0)); 
    for (int i = e+1; i < n; ++i) 
      ans = max(ans, v[i]-k*abs(pos[i]-pos[e])+dp(s,i,k-1,1));  
  }
  return ans; 
}

int main() { 
  int t; 
  scanf("%d", &t); 
  for (kase = 1; kase <= t; ++kase) {
    scanf("%d", &n); 
    for (int i = 0; i < n; ++i) scanf("%d", &pos[i]); 
    for (int i = 0; i < n; ++i) scanf("%d", &v[i]); 
    
    int ans = 0; 
    for (int k = 1; k <= n; ++k) 
      for (int i = 0; i < n; ++i) 
        ans = max(ans, v[i]-k*abs(pos[i])+dp(i,i,k-1,0));
    printf("%d
", ans); 
  }
  return 0;
}
原文地址:https://www.cnblogs.com/yifeiWa/p/11320202.html