【题解】CF82D Two out of Three

【题目大意】

一队顾客排在一位收银员前面。

他采取这样一个策略:每次,假如队伍有至少两人,就会从前面的前三人(如果有)中选取两位一起收银,所花费的时间为这两人单独收银所需时间的最大值;如果只有两人,那么一起收银;如果只有一人,那么单独收银。

请问所需的总时间最少是多少,以及总时间最少的方案。(\(1\leq n\leq1000,1\leq a_i\leq 10^6\)

提交地址


\(f_{i,j}\) 代表当前三个人中选择的两个人为第 \(i\) 个和第 \(j\) 个人的时候,最少花费的时间(\(i<j\))。

状态转移方程为:

\[\large f(i,j)=\min\begin{cases}\max(a_i,a_j)+f(j+1,j+2) \\\max(a_i,a_{j+1})+f(j,j+2)\\ \max(a_j,a_{j+1})+f(i,j+2)\end{cases} \]

我们可以用记忆化搜索实现。

至于输出方案,我们可以再进行一遍深搜,判断当前状态是由哪一状态转移过来的。

代码如下:

#include<bits/stdc++.h>
#define rint register int
using namespace std;
inline int read(){
    int s=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
    while(c>='0'&&c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();
    return f?s:-s;
}
int n,f[1010][1010],a[1010];
int dfs(int x,int y){
    if(f[x][y]) return f[x][y];
    if(y==n+1) return f[x][y]=a[x];
    if(y==n) return f[x][y]=max(a[x],a[y]);
    f[x][y]=max(a[x],a[y])+dfs(y+1,y+2);
    f[x][y]=min(f[x][y],max(a[x],a[y+1])+dfs(y,y+2));
    f[x][y]=min(f[x][y],max(a[y],a[y+1])+dfs(x,y+2));
    return f[x][y];
}
void Print(int x,int y){
    if(y==n+1) return printf("%d\n",x),void();
    if(y==n) return printf("%d %d\n",x,y),void();
    if(f[x][y]==max(a[x],a[y])+f[y+1][y+2])
        printf("%d %d\n",x,y),Print(y+1,y+2);
    else if(f[x][y]==max(a[x],a[y+1])+f[y][y+2])
        printf("%d %d\n",x,y+1),Print(y,y+2);
    else if(f[x][y]==max(a[y],a[y+1])+f[x][y+2])
        printf("%d %d\n",y,y+1),Print(x,y+2);
}
int main(){
    n=read();
    for(rint i=1;i<=n;i++) a[i]=read();
    dfs(1,2);
    printf("%d\n",f[1][2]);
    Print(1,2);
    return 0;
}
posted @ 2020-09-20 14:44  LCGUO  阅读(212)  评论(0编辑  收藏  举报