UVA - 10051Tower of Cubes(递推)

题目: UVA - 10051Tower of Cubes(递推)

题目大意:给出N个正方体1-N,只有序号小的正方体可以放在序号大的正方体的上面,并且除了最底下的那个正方体,其他的正方体的底面要和它下面的正方体的上面颜色相同。问怎样组合才能使得用的正方体个数越多。并且输出其中的一种堆放方式。

解题思路:一开始觉得是用DAG上的DP来做,结果状态开太多dp【N】【N】【M】(N代表正方体个数, M代表六个面),最后输出路径的时候超时了。后面看了别人的题解,发现状态只需要开dp[N][M]就足够了,因为只要在意这个正方体是哪个面在上面,下面的正方体的范围是确定的,那么组成方式最优的肯定是确定的。不需要将下面接着哪个正方体也记录下来。

状态转移方程:dp【i】【k】 = (dp【i + n】【m】 + 1) m:和第i个正方体底面颜色相同的i + n个正方体的那个面。 i  + n 代表i之后的正方体从哪个开始。意思就是从i之后的正方体任选一个作为i后面的那个正方体,然后在用这个i + n的正方题的m面朝上的最多的个数再加上1.

初始化的时候要小心,dp【i】【k】 = 1[(i >= 1 && i <= N) (k >= 0 && k < M)】只取一个的时候,任何一个正方体哪个面朝上的组合方式的最多的个数是1。

这题的路径打印也是很无语,还得先找到对的路径,然后用next【j】(j这个立方体后面接哪个立方体最优),和side【j】(j这个立方体哪个面朝上最优)记录下来,最后在打印出来。

代码:

#include <cstdio>
#include <cstring>

const int N = 505;
const int M = 6;
const char str[M][2 * M] = {"front", "left", "top", "bottom", "right", "back"};

int n;
int cube[N][M];
int dp[N][M];

int next[N], side[N];

int Max (const int a, const int b) {return a > b? a: b;}

bool printf_ans (int d, int k) {

	if (dp[d][k] == 1) {
		next[d] = d;
		return true;
	}

	for (int j = d + 1; j <= n; j++)
		for (int i = 0; i < M; i++)
			if (cube[d][M - 1 - k] == cube[j][i] && dp[d][k] == dp[j][i] + 1) {
				if (printf_ans(j, i)) {
					next[d] = j;
					side[j] = i;
					return true;
				}
			}
	return false;
}

int main () {

	int cas = 0;
	while (scanf ("%d", &n) , n) {

		if (cas)
			printf ("\n");

		for (int i = 1; i <= n; i++) {
			for (int j = 0; j < M/2; j++)
				scanf ("%d%d", &cube[i][j], &cube[i][M - 1 - j]);
		}
		//init
		for (int j = 1; j <= n; j++)
			for (int i = 0; i < M; i++)
				dp[j][i] = 1;

		int ans = 1;
		int d, k;
		for (int i = n - 1; i >= 1; i--)
			for (int j = 0; j < M; j++) {

				for (int l = i + 1; l <= n; l++) {
					for (int k = 0; k < M; k++)
						if (cube[i][M - 1 - j] == cube[l][k]) {

							if (dp[l][k] + 1 > dp[i][j]) {

								dp[i][j] = Max (dp[i][j], dp[l][k] + 1);
							}
						}
				} 

				if (dp[i][j] > ans) {

					d = i;
					k = j;
					ans = dp[i][j];
				}
			}

		printf ("Case #%d\n%d\n", ++cas, ans);

		//path
		if (ans == 1) {

			printf ("1 front\n");
			continue;
		}

		printf_ans (d, k);

		while (1) {

			printf ("%d %s\n", d, str[k]);
			if (d == next[d])
				break;
			d = next[d];
			k = side[d];
		}
	}
	return 0;
}

UVA - 10051Tower of Cubes(递推)

时间: 2024-08-29 05:06:42

UVA - 10051Tower of Cubes(递推)的相关文章

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

题目链接:uva 1478 - Delta Wave 题目大意:对于每个位置来说,可以向上,水平,向下,坐标不能位负,每次上下移动最多为1, 给定n问说有多少种不同的图.结果对10100取模. 解题思路:因为最后都要落回y=0的位置,所以上升的次数和下降的次数是相同的,并且上升下降的关系满足出栈入栈的关系.即卡特兰数. 所以每次枚举i,表示有i个上升,i个下降,用组合数学枚举出位置,然后累加求和. C(2?in)?f(i)=C(2?i?2n)?f(i?1)?(n?2?i+1)?(n?2?i+2)

【UVA】12034-Race(递推,组合数打表)

递推公式,假设第一名有i个人并列,那么: f[n] = C(n,i) * f[n - i]; 打出1 ~ 1000的所有组合数,之后记忆化搜索,需要打表. 14026995 12034 Race Accepted C++ 0.032 2014-08-12 11:47:47 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector&g

UVA - 620Cellular Structure(递推)

题目:UVA - 620Cellular Structure(递推) 题目大意:只能给出三种细胞的增殖方式,然后给出最后细胞的增殖结果,最后问你这是由哪一种增殖方式得到的.如果可以由多种增殖方式得到,就输出题目中列出来的增殖方式靠前的那种. 解题思路:也是递推,细胞长度长的可以由细胞长度短的推得,并且这里第一种只能是长度为1的细胞才有可能,所以判断的时候可以3个判断,看能否与上面的增殖结果匹配,可以的话就记录下来,以后的长串就是由这样的短串再加上两个细胞继续往后推. 例如: BAABA 将A变为

uva 1485 - Permutation Counting(递推)

题目链接:uva 1485 - Permutation Counting 题目大意:给定n和k,要求求一个由1~n组成的序列,要求满足ai>i的i刚好有k个的序列种数. 解题思路:dp[j][i]表示长度为i,j个位置满足的情况. dp[j+1][i]+=dp[j][i]?(j+1); 1, (3), (4), 2: 括号位置代表ai>i,既满足位置,此时i = 4, j = 2. -> 1, (3), (4), 2, 5 1 种,在最后追加 -> 1, (5), (4), 2,

UVA - 10003Cutting Sticks(递推)

题目:UVA - 10003Cutting Sticks(递推) 题目大意:给根木棍长度l,现在要锯这根木棍,给出n个锯点,求怎样锯才能使得开销最小.例如 长度为10的木棍, 锯点2 4 7,那么如果按照这个顺序 , 首先显示由长度位10的木头先锯了2 ,开销就加10,然后锯完现在有[0,2]和[2,10]长度分别为2 ,8的木棍,现在要在4这个位置锯木头,就是在长度为8的木头上锯4这个位置,这样就加上8,然后又有长度为[2,4][4,10]的木头,最后要锯7的话,就需要开销加上6.所以开销就是

UVA 11021 - Tribles(概率递推)

UVA 11021 - Tribles 题目链接 题意:k个毛球,每个毛球死后会产生i个毛球的概率为pi,问m天后,所有毛球都死亡的概率 思路:f[i]为一个毛球第i天死亡的概率,那么 f(i)=p0+p1f(i?1)+p2f(i?1)2+...+pnf(i?1)n 然后k个毛球利用乘法定理,答案为f(m)k 代码: #include <stdio.h> #include <string.h> #include <math.h> const int N = 1005;

UVA 10288 - Coupons(概率递推)

UVA 10288 - Coupons 题目链接 题意:n个张票,每张票取到概率等价,问连续取一定次数后,拥有所有的票的期望 思路:递推,f[i]表示还差i张票的时候期望,那么递推式为 f(i)=f(i)?(n?i)/n+f(i?1)?i/n+1 化简后递推即可,输出要输出分数比较麻烦 代码: #include <cstdio> #include <cstring> #include <cmath> long long gcd(long long a, long lon

UVA 1350 - Pinary(数论+递推)

题目链接:1350 - Pinary 题意:二进制数,不能有连续的1,给定第n个数字,输出相应的二进制数 思路:先是递推,求出由n位组成的数字中有几个满足条件 dp[i] = dp[i - 1] + dp[i - 2],考虑最后一位放0和倒1位放0的情况. 然后用一个sum[i]记录满足<=i位一共的情况 接着利用二分找到给定的n > sum[i - 1],i的最大值,这个就是所求的答案的最高位. 因为如果这位放1,那么就会一共多sum[i - 1] + 1个数,那么就还需要添加n - (su

uva 1073 - Glenbow Museum(递推)

cocos2d-x升级到3.0后变化不小,除了API的变化(主要是函数和类名称变化,以及使用了C++11的不少特性,function/bind, lamda, std::thread-),创建和编译工程也做了一些简化调整.本文主要讨论一下cocos2d-x3.0 在android平台开发的环境设置及工程创建编译流程. 1.   初始设置 除了2.x所需要的python,jdk, android sdk和ndk之外,还需要部署apache-ant. 1)      在path中设置好java环境变