非常好的题!和spoj 的 Mobile Service有点相似,用记忆化搜索很容易解决
看了网上的题解,也是减掉一维,刚好可以开下数组 https://blog.lucien.ink/archives/224/
#include<bits/stdc++.h> using namespace std; #define maxn 2005 int n,A[maxn],B[maxn]; int dp[maxn][11][11][11][11]; //状态:准备去拉第i个人,当前在cur楼,另外三个人的目标楼层是abc int dfs(int i,int cur,int a,int b,int c){ if(dp[i][cur][a][b][c]!=-1) return dp[i][cur][a][b][c]; int res=0x3f3f3f3f; if(i>n){//终止状态,只要把abc送到终点即可 if(!a && !b && !c)res=0; if(a!=0)res=min(res,dfs(i,a,0,b,c)+abs(cur-a)+1);//送到a if(b!=0)res=min(res,dfs(i,b,a,0,c)+abs(cur-b)+1);//送到b if(c!=0)res=min(res,dfs(i,c,a,b,0)+abs(cur-c)+1);//送到c return dp[i][cur][a][b][c]=res; } //先放下abc的决策 if(a)res=min(res,dfs(i,a,0,b,c)+abs(cur-a)+1); if(b)res=min(res,dfs(i,b,a,0,c)+abs(cur-b)+1); if(c)res=min(res,dfs(i,c,a,b,0)+abs(cur-c)+1); //准备去拉一个人的决策:先去把i接上电梯 if(a&&b&&c){//电梯全满,再拉一个人需要先放下一个人 res=min(res,dfs(i+1,B[i],a,b,c)+abs(cur-A[i])+abs(A[i]-B[i])+2); res=min(res,dfs(i+1,a,B[i],b,c)+abs(cur-A[i])+abs(A[i]-a)+2); res=min(res,dfs(i+1,b,a,B[i],c)+abs(cur-A[i])+abs(A[i]-b)+2); res=min(res,dfs(i+1,c,a,b,B[i])+abs(cur-A[i])+abs(A[i]-c)+2); } else {//先去接i,再拉一个人 if(!a)res=min(res,dfs(i+1,A[i],B[i],b,c)+abs(cur-A[i])+1); else if(!b)res=min(res,dfs(i+1,A[i],a,B[i],c)+abs(cur-A[i])+1); else if(!c)res=min(res,dfs(i+1,A[i],a,b,B[i])+abs(cur-A[i])+1); } return dp[i][cur][a][b][c]=res; } int main(){ memset(dp,-1,sizeof dp); cin>>n; for(int i=1;i<=n;i++)cin>>A[i]>>B[i]; cout<<dfs(1,1,0,0,0)<<' '; }
此外是滚动数组的版本(没有降维复杂度比较高)
#include<bits/stdc++.h> using namespace std; #define maxn 2005 int n,a[maxn],b[maxn],dp[2][11][11][11][11][11]; void calc(int &a,int b){ int tmp=min(a,b); a=tmp; } int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i]>>b[i]; memset(dp,0x3f,sizeof dp); int cur=0; dp[cur][1][0][0][0][0]=2*n;//开始停在1楼,因为n个人总共上下2*n次,所以直接加上这个值 for(int i=0;i<=n;i++){//去接第i+1个人 for(int x=9;x>=0;x--)//这里必须逆序,因为把电梯里的人放下时的目标状态是dp[cur][][0][0][0][0],即消除掉后效性 for(int y=9;y>=0;y--) for(int z=9;z>=0;z--) for(int w=9;w>=0;w--) for(int f=1;f<=9;f++){ int now=dp[cur][f][x][y][z][w]; if(now==0x3f3f3f3f)continue; if(x==0 && i<n)//把第i+1个人放在位置x,更新状态到下一步 calc(dp[cur^1][a[i+1]][b[i+1]][y][z][w],now+abs(f-a[i+1])); else if(x)//不接人把电梯里的人送到目的地 calc(dp[cur][x][0][y][z][w],now+abs(f-x)); if(y==0 && i<n) calc(dp[cur^1][a[i+1]][x][b[i+1]][z][w],now+abs(f-a[i+1])); else if(y) calc(dp[cur][y][x][0][z][w],now+abs(f-y)); if(z==0 && i<n) calc(dp[cur^1][a[i+1]][x][y][b[i+1]][w],now+abs(f-a[i+1])); else if(z) calc(dp[cur][z][x][y][0][w],now+abs(f-z)); if(w==0 && i<n) calc(dp[cur^1][a[i+1]][x][y][z][b[i+1]],now+abs(f-a[i+1])); else if(w) calc(dp[cur][w][x][y][z][0],now+abs(f-w)); } if(i<n){ memset(dp[cur],0x3f,sizeof dp[cur]); cur^=1; } } int ans=0x3f3f3f3f; for(int i=1;i<=9;i++) ans=min(ans,dp[cur][i][0][0][0][0]); cout<<ans<<' '; }