UVA The Tower of Babylon(437)

题目大意:

       有n种长宽高为x,y,z的砖头,每种都有无数个。砖头可以用不同方式来盖,砖头a以某种方式可以盖在砖头b上,当且仅当a的底部的长宽都要比b的底部长宽要小。问最高可以建多高?

 

解题思路:

       动态规划中的最长递增(递减)子序列问题,每个砖头可以看成是3个砖头,即A(x,y,z) , B(x,z,y) 和 C(y,z,x),其中前两个为底,大三个元素为高,然后将所有砖头进行排序,长宽小的排前面,即 (x1 < x2 && y1 < y2 ) || ( x1 < y2 && y1 < x2 ) || ( x1*y1 < x2*y2 ), 其中第三个条件为面积小的放前面,当不能满足前两个条件时,若面积大的放前面会出错,具体为什么我没弄清楚,但两者我都试过,必须得把面积小的放前面。

       排好序后,接下来就是求最大递增子序列了,只要把原来求子序列长度改为高度即可。状态转移方程为:

dp[i] = max( dp[i], dp[j]+v[i][2] );

其中v[i][2]表示第i个砖头的高度。dp[i]表示第i个砖头能够搭成的最高高度。

 

代码:

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

bool cmp( vector<int> v1, vector<int> v2 )
{
	return ( (v1[0]<v2[0] && v1[1]<v2[1]) || ( v1[0]<v2[1] && v1[1]<v2[0] ) || (v1[0]*v1[1] < v2[0]*v2[1]) );
}

int dp[30000] = {1};

int main()
{
	freopen( "test.txt", "r", stdin );

	int T = 1;
	int N;
	int value1, value2, value3;

	while( cin>>N, N )
	{
		memset(dp,0,sizeof(dp) );

		vector<int> temp;
		vector< vector<int> > v;
		for( int i = 0; i < N; i++ )
		{
			cin>>value1>>value2>>value3;
			temp.push_back(value1);
			temp.push_back(value2);
			temp.push_back(value3);
			v.push_back(temp);
			temp.clear();
			temp.push_back(value1);
			temp.push_back(value3);
			temp.push_back(value2);
			v.push_back(temp);
			temp.clear();
			temp.push_back(value2);
			temp.push_back(value3);
			temp.push_back(value1);
			v.push_back(temp);
			temp.clear();
		}

		sort( v.begin(), v.end(), cmp );

		for( int i = 0; i < 3*N; i++ )
		{
			dp[i] = v[i][2];
		}

		for( int i = 3*N-2; i >= 0; i-- )
		{
			for( int j = i+1; j < 3*N; j++ )
			{
				if( ((v[j][0] > v[i][0]) && (v[j][1] > v[i][1])) || ((v[j][0] > v[i][1]) && (v[j][1] > v[i][0])) )
					dp[i] = max( dp[i], dp[j]+v[i][2] );
			}
		}

		sort(dp,dp+(3*N));
		cout<<"Case "<<T<<": maximum height = "<<dp[3*N-1]<<endl;
		T++;
	}

	return 0;
}

 

你可能感兴趣的:(uva)