uvaoj 10051 Tower of Cubes 最长上升子序列 记录路径

从轻到重给定了n个正方体,每个正方体的每个面都有一种颜色,颜色用一个整数表示,要建造一个塔,不能将重的放在轻的正方体上,尽可能建造高的塔,并且要求相邻面的颜色一样。这个类似于最长上升子序列,用dp[i][j]表示第i个正方体的j面朝上时建造的最高的塔的高度,用pre[i][j]记录dp[i][j]的前驱的状态(第几个的那个面),有了状态的表示,很容易就可以推出转移方程,要注意题目的要求,即相邻的面的颜色一样。
写了四层循环,复杂度为10^6级别。
代码如下:
/*************************************************************************
	> File Name: 10051.cpp
	> Author: gwq
	> Mail: gwq5210@qq.com 
	> Created Time: 2014年12月22日 星期一 18时23分51秒
 ************************************************************************/

#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())

using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;

const double esp = 1e-5;

#define N 510

struct Node {
	// 0-5分别代表前后左右上下
	int face[10];
	int idx;
	int top, bottom;
	void input(void)
	{
		for (int i = 0; i < 6; ++i) {
			scanf("%d", &face[i]);
		}
	}
}node[N];

struct Rec {
	int idx1, idx2;
};

// dp[i][j]表示第i个方块j面朝上时候的最高高度
int n, dp[N][10];
// 记录dp[i][j]的前一个方块的状态(第几个和那个面朝上)
Rec pre[N][10];
int mp[] = {1, 0, 3, 2, 5, 4};
char str[][N] = {"front", "back", "left", "right", "top", "bottom"};

int main(int argc, char *argv[])
{
	int c = 0;
	while (scanf("%d", &n) != EOF) {
		if (n == 0) {
			break;
		}
		for (int i = 1; i <= n; ++i) {
			node[i].input();
			node[i].idx = i;
		}
		clr(dp, 0);
		clr(pre, -1);
		for (int i = 0; i < 6; ++i) {
			dp[1][i] = 1;
		}
		for (int i = 2; i <= n; ++i) {
			for (int j = 0; j < 6; ++j) {
				dp[i][j] = 1;
				for (int k = 1; k < i; ++k) {
					for (int l = 0; l < 6; ++l) {
						if (node[i].face[mp[j]] == node[k].face[l]) {
							if (dp[i][j] < dp[k][l] + 1) {
								dp[i][j] = dp[k][l] + 1;
								pre[i][j].idx1 = k;
								pre[i][j].idx2 = l;
							}
						}
					}
				}
			}
		}
		int idx1 = 1;
		int idx2 = 0;
		for (int i = 1; i <= n; ++i) {
			for (int j = 0; j < 6; ++j) {
				if (dp[idx1][idx2] < dp[i][j]) {
					idx1 = i;
					idx2 = j;
				}
			}
		}
		printf("Case #%d\n", ++c);
		printf("%d\n", dp[idx1][idx2]);
		stack<Rec> q;
		int cur1 = idx1;
		int cur2 = idx2;
		while (cur1 != -1) {
			Rec u;
			u.idx1 = cur1;
			u.idx2 = cur2;
			q.push(u);
			int tmp = pre[cur1][cur2].idx1;
			cur2 = pre[cur1][cur2].idx2;
			cur1 = tmp;
		}
		while (!q.empty()) {
			Rec u = q.top();
			printf("%d %s\n", u.idx1, str[mp[u.idx2]]);
			q.pop();
		}
		printf("\n");
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值