UVA - 1628 Pizza Delivery (深入分析问题)

问题

分析

这道题和之前的修缮长城有点相似
区别是范围时间损失被简化了,但是可以选择一些顾客不送,也就是跳过他们,这就引入了一个问题,那就是没办法将损失累积到一个顾客上面(因为不知道到底要服务多少个顾客),然后将时间归0,所以在dp[i][j][2]的基础上增加一个维度,用来表示服务的顾客数量(有一些顾客被放弃了),然后我们就可以按照修缮长城的做法了
dp[i][j][k][pos] 已经处理了[i,j]顾客(不管送还是没送),现在在位置pos(0代表i,1代表j),还要送剩余k个顾客时,剩下k个顾客能给的最大收入
状态转移方程: 可以选择左边的点或者右边的点
左边的点i: d p ( l e f t , r i g h t , c n t , p o s ) = m a x ( d p ( l e f t , r i g h t , c n t , p o s ) , e [ i ] c n t ( p [ p o s ] p [ i ] ) + D P ( i , r i g h t , k 1 , 0 ) ) , 0 < = i < l e f t dp(left,right,cnt,pos)=max(dp(left,right,cnt,pos), e[i]-cnt*(p[pos]-p[i])+DP(i,right,k-1,0)),0<=i<left
右边的点j: d p ( l e f t , r i g h t , c n t , p o s ) = m a x ( d p ( l e f t , r i g h t , c n t , p o s ) , e [ j ] c n t ( p [ j ] p [ p o s ] ) + D P ( l e f t , j , k 1 , 1 ) ) , r i g h t < j < n dp(left,right,cnt,pos)=max(dp(left,right,cnt,pos), e[j]-cnt*(p[j]-p[pos])+DP(left,j,k-1,1)),right<j<n
*cnt(p[pos]-p[i])**就是损失的累计,我们必须先知道cnt才能计算它,所以要遍历for(int k=1;k<=n;++k) cnt这个数的值,才能累计损失在一个点上,将时间归为0,方便求解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;
const int maxn=100+5;  //客人总数
int p[maxn],e[maxn]; //position,earn
//dp[i][j][k][p] 已经处理了[i,j]顾客(不管送还是没送),现在在位置p(0代表i,1代表j),还要送剩余k个顾客时,剩下k个顾客能给的最大收入
int dp[maxn][maxn][maxn][2],vis[maxn][maxn][maxn][2],kase=1,T,n;

int DP(int left,int right,int cnt,int pos){
    if(cnt==0) return 0;
    int &ans=dp[left][right][cnt][pos];
    if(vis[left][right][cnt][pos]==kase) return ans;
    vis[left][right][cnt][pos]=kase;
    ans=0;
    if(pos){ //人位于right
        for(int i=0;i<left;++i){  //有一些人被跳过了,不处理,下一个处理左边的i
            ans=max(ans,e[i]-cnt*(p[right]-p[i])+DP(i,right,cnt-1,0));
        }
        for(int i=right+1;i<n;++i){  //下一个处理右边的人,但有可能跳过right+1
            ans=max(ans,e[i]-cnt*(p[i]-p[right])+DP(left,i,cnt-1,1));
        }
    }else{  //人位于left
        for(int i=0;i<left;++i){
            ans=max(ans,e[i]-cnt*(p[left]-p[i])+DP(i,right,cnt-1,0));
        }
        for(int i=right+1;i<n;++i){
            ans=max(ans,e[i]-cnt*(p[i]-p[left])+DP(left,i,cnt-1,1));
        }
    }
    return ans;
}

int main(void){
    cin>>T;
    while(kase<=T){
        cin>>n;
        for(int i=0;i<n;++i) scanf("%d",&p[i]);
        for(int i=0;i<n;++i) scanf("%d",&e[i]);
        int ans=0;  //ans=0可以看作最差一个人也不送
        //处理有的客人不送时,方法比较巧妙
        for(int k=1;k<=n;++k){  //只送给k个客人,其他的客人不送
            for(int i=0;i<n;++i){
                ans=max(ans,e[i]-k*abs(p[i])+DP(i,i,k-1,0)); //只送给k个客人,第i个客人先被送餐,在它上面累计这段时间的损失
            }
        }
        printf("%d\n",ans);
        ++kase;
    }
}
发布了15 篇原创文章 · 获赞 0 · 访问量 162

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/104066102