思路:LIS变形题,状态转移方程并不难想。
i表示第i个立方体,j1表示正面,j2表示底面
那么 dp[i][j2]=max{dp[i-1][j1]+1,dp[i][j2]} 每个立方体有两种状态用或者不用,通过颜色匹配来转移。
之前一度让我纠结的就是该如何输出过程也就是构造最优解。因为它是通过颜色来转移的,而且要求输出哪个面,而且对于每个立方体不是每种颜色都可以改变。因此让我很是纠结。后来过了一段时间重新做这个题,每次使用这个立方体的时候都记录下使用的是哪个面。然后递归输出最优解,如果dp[i][j2]=dp[i-1][j2]则表示没有使用第i个立方体,因此i变成i-1,重复判断。如果dp[i][j2]!=dp[i-1][j2],那肯定是使用了第i个立方体了,然后通过之前的记录数组找到是使用了哪个面,同时由面对应到第i-1个立方体底面的颜色。再递归直到层数为0即可。
rank跑了个85,还不错~
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define MAXN 100 using namespace std; struct Cube { int face[10]; }; int dp[505][105]; int note[505][105]; int n; Cube p[505]; int getback(int a) { if(a==1) return 2; if(a==2) return 1; if(a==3) return 4; if(a==4) return 3; if(a==5) return 6; if(a==6) return 5; } void PrintFace(int a,int b) { printf("%d ",a); if(b==1)puts("front"); else if(b==2) puts("back"); else if(b==3) puts("left"); else if(b==4) puts("right"); else if(b==5) puts("top"); else if(b==6) puts("bottom"); } void OutPut(int i,int j,int ans) { if(ans==0) return ; while(dp[i][j]==dp[i-1][j]&&i-1) i=i-1; int use=note[i][j]; OutPut(i-1,p[i].face[use],ans-1); PrintFace(i,use); } int main() { int kase=0; while(scanf("%d",&n)&&n) { memset(dp,0,sizeof(dp)); memset(note,0,sizeof(note)); for(int i=1; i<=n; ++i) for(int j=1; j<=6; ++j) scanf("%d",&p[i].face[j]); for(int i=1; i<=n; ++i) { for(int j=1; j<=MAXN; ++j) dp[i][j]=dp[i-1][j]; for(int j=1; j<=6; ++j) { int top=p[i].face[j],bak=p[i].face[getback(j)]; if(dp[i-1][top]+1>dp[i][bak]) { dp[i][bak]=dp[i-1][top]+1; note[i][bak]=j; } } } int ans=0,tt; for(int i=1; i<=MAXN; ++i) if(dp[n][i]>ans) { ans=dp[n][i]; tt=i; } if(kase) printf("\n"); printf("Case #%d\n",++kase); printf("%d\n",ans); OutPut(n,tt,ans); } return 0; }