【題解】CF82D Two out of Three
阿新 • • 發佈:2020-09-20
【題目大意】
一隊顧客排在一位收銀員前面。
他採取這樣一個策略:每次,假如隊伍有至少兩人,就會從前面的前三人(如果有)中選取兩位一起收銀,所花費的時間為這兩人單獨收銀所需時間的最大值;如果只有兩人,那麼一起收銀;如果只有一人,那麼單獨收銀。
請問所需的總時間最少是多少,以及總時間最少的方案。(\(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; }