Problem A: Tower of Cubes
In this problem you are given
N
colorful cubes each having a distinct weight. Each face of a cube is colored with one color. Your job is to build a tower using the cubes you have subject to the following restrictions:
Problem A: Tower of Cubes |
- Never put a heavier cube on a lighter one.
- The bottom face of every cube (except the bottom cube, which is lying on the floor) must have the same color as the top face of the cube below it.
- Construct the tallest tower possible.
Input
The input may contain multiple test cases. The first line of each test case contains an integer N ( ) indicating the number of cubes you are given. The i th ( ) of the next N lines contains the description of the i th cube. A cube is described by giving the colors of its faces in the following order: front, back, left, right, top and bottom face. For your convenience colors are identified by integers in the range 1 to 100. You may assume that cubes are given in the increasing order of their weights, that is, cube 1 is the lightest and cube N is the heaviest.The input terminates with a value 0 for N.
Output
For each test case in the input first print the test case number on a separate line as shown in the sample output. On the next line print the number of cubes in the tallest tower you have built. From the next line describe the cubes in your tower from top to bottom with one description per line. Each description contains an integer (giving the serial number of this cube in the input) followed by a single whitespace character and then the identification string (front, back, left, right, top or bottom) of the top face of the cube in the tower. Note that there may be multiple solutions and any one of them is acceptable.
Print a blank line between two successive test cases.
Sample Input
3 1 2 2 2 1 2 3 3 3 3 3 3 3 2 1 1 1 1 10 1 5 10 3 6 5 2 6 7 3 6 9 5 7 3 2 1 9 1 3 3 5 8 10 6 6 2 2 4 4 1 2 3 4 5 6 10 9 8 7 6 5 6 1 2 3 4 7 1 2 3 3 2 1 3 2 1 1 2 3 0
Sample Output
Case #1 2 2 front 3 front Case #2 8 1 bottom 2 back 3 right 4 left 6 top 8 front 9 front 10 top一开始看到这题,我就知道这个是DAG上的dp,记得之前做过两道类似的题,uva103堆砌盒子,那道题是个多维嵌套,只有前者每个维度严格小于后者时,前者才能嵌套于后者,还有一题是uva437巴比伦塔,那题与这题非常类似,也是往上叠塔,只是巴比伦那题每块可以多次利用,因此难度比这题小。
这道题我初看是要将一个块转化成6个,但有且只能用一个,在程序里我考虑被6除,商相同算同一个,这样被6除不同的商才能递推,于是解决了一种只能用一次的问题。
但是我在写程序时还是发现了一个棘手的问题,其实是我题目的一个条件忽略了,这题还有一个条件,就是重量轻的才能放重量重的上面,不要小看这个条件,只有这个条件保证,才能使这道题化为DAG上的dp,因为这样才是无环的无向图啊,否则问题就很棘手。就像我一开始忽略这个条件,我感觉要枚举每个环的结点作为塔的底部,即dp=1;
这样发现程序写不出来了!
记忆化搜索代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 3010
using namespace std;
struct cube{
int top,bottom,td;
}p[Maxn];
int tot;
int a[6],road[Maxn],dp[Maxn];
char s[][10]={"front","back","left","right","top","bottom"};
int dfs(int x){
int &ans=dp[x];
if(ans) return ans;
bool flag=true;
for(int i=(x/6+1)*6;i<tot;i++)
if(p[x].bottom==p[i].top){
int t=dfs(i)+1;
if(t>ans){
ans=t;
road[x]=i;flag=false;
}
}
if(flag) return ans=1;
return ans;
}
int main()
{
int n,cas=1,maxi;
while(scanf("%d",&n),n){
if(cas!=1) puts("");
tot=0;
for(int i=1;i<=n;i++){
for(int j=0;j<6;j++){
scanf("%d",a+j);
p[tot++]=cube{a[j],0,j};
}
for(int j=1;j<=6;j++)
if(j&1) p[tot-j].bottom=a[5-j];
else p[tot-j].bottom=a[7-j];
}
int ans=0;
memset(dp,0,sizeof dp);
for(int i=0;i<tot;i++)
if(dp[i]==0) dfs(i);
for(int j=0;j<tot;j++)
if(dp[j]>ans){ans=dp[j];maxi=j;}
printf("Case #%d\n%d\n",cas++,ans);
for(int i=ans;i>0;i--){
printf("%d %s\n",maxi/6+1,s[p[maxi].td]);
maxi=road[maxi];
}
}
return 0;
}
递推代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 3010
using namespace std;
struct cube{
int top,bottom,td;
}p[Maxn];
int tot;
int a[6],road[Maxn],dp[Maxn];
char s[][10]={"front","back","left","right","top","bottom"};
int main()
{
int n,cas=1,maxi;
while(scanf("%d",&n),n){
if(cas!=1) puts("");
tot=0;
for(int i=1;i<=n;i++){
for(int j=0;j<6;j++){
scanf("%d",a+j);
p[tot++]=cube{a[j],0,j};
}
for(int j=1;j<=6;j++)
if(j&1) p[tot-j].bottom=a[5-j];
else p[tot-j].bottom=a[7-j];
}
for(int i=0;i<tot;i++) dp[i]=1;
for(int i=tot-7;i>=0;i--){
for(int j=(i/6+1)*6;j<tot;j++)
if(p[i].bottom==p[j].top&&dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
road[i]=j;
}
}
int ans=0;
for(int j=0;j<tot;j++)
if(dp[j]>ans){ans=dp[j];maxi=j;}
printf("Case #%d\n%d\n",cas++,ans);
for(int i=ans;i>0;i--){
printf("%d %s\n",maxi/6+1,s[p[maxi].td]);
maxi=road[maxi];
}
}
return 0;
}
如果觉得化成一维吃力的话,可以加一维来dp,可以参考点击打开链接