搜狐2016编程题——叠罗汉[未完]

搜狐员工小王最近利用假期在外地旅游,在某个小镇碰到一个马戏团表演,精彩的表演结束后发现团长正和大伙在帐篷前激烈讨论,小王打听了下了解到, 马戏团正打算出一个新节目“最高罗汉塔”,即马戏团员叠罗汉表演。考虑到安全因素,要求叠罗汉过程中,站在某个人肩上的人应该既比自己矮又比自己瘦,或相等。 团长想要本次节目中的罗汉塔叠的最高,由于人数众多,正在头疼如何安排人员的问题。小王觉得这个问题很简单,于是统计了参与最高罗汉塔表演的所有团员的身高体重,并且很快找到叠最高罗汉塔的人员序列。 现在你手上也拿到了这样一份身高体重表,请找出可以叠出的最高罗汉塔的高度,这份表中马戏团员依次编号为1到N。

输入描述:
首先一个正整数N,表示人员个数。 
之后N行,每行三个数,分别对应马戏团员编号,体重和身高。


输出描述:
正整数m,表示罗汉塔的高度。

输入例子:
6
1 65 100
2 75 80
3 80 100
4 60 95
5 82 101
6 81 70

输出例子:
4

思路:
根据例子,没问叠罗汉的具体高度值,问的是能叠多少个人。
细化后觉得就是两种条件的排列,体重排一次,身高排一次。
实现上,做了一次排序,做了一次计数,第一次降序排体重,第二次看身高是否符合降序,不符合的就用计数器计下来,最后得出符合条件的数量。

自己的解答

#include<iostream>
using namespace std;
struct person{
	unsigned int id;
	unsigned int weight;
	unsigned int height;
};
int main(){
	int count = 0;
	cin>>count;
	struct person P[count];
	int i = 0;
	unsigned idInput,weightInput,heightInput;
	for(i = 0; i < count; i++)
	{
		cin>>P[i].id>>P[i].weight>>P[i].height;
	}

	//第一次排序,体重从大到小
	unsigned int tmpId,tmpWeight,tmpHeight;
	for(i = 0;i < count;i++)
	{
		for(int j = count - 1;j > i;j--)
		{
			if(
			(P[i].weight < P[j].weight)||
			((P[i].weight == P[j].weight)&&
			(P[i].height<P[j].height)))

//			if(P[i].weight < P[j].weight)
			{
				tmpId = P[i].id;
				tmpWeight = P[i].weight;
				tmpHeight = P[i].height;
				P[i].id = P[j].id;
				P[i].weight = P[j].weight;
				P[i].height = P[j].height;
				P[j].id = tmpId;
				P[j].weight = tmpWeight;
				P[j].height = tmpHeight;
			}
		}

	}
	for(int i = 0;i < count;i++)
	{
	//	cout << "id:"<<P[i].id<<" weight:"<<P[i].weight<<" height:"<<P[i].height<<endl;
	}	
//	cout << "count : "<< count << endl;
	//排除身高顺序不符合的
	unsigned int m = count;//最终结果m,罗汉层数
	for(i = 0;i < count;i++)
	{
		//cout <<"P[i = "<<i<<"].height is "<<P[i].height;
		for(int j = count - 1;j >= i;j--)
		{
	//		cout << " j:"<<j<<endl;
			if(P[i].height < P[j].height)
			{
			//	cout << "pi's height: "<<P[i].height<<"   pj's height: "<<P[j].height<<endl;
				//cout << endl << "P[j = "<<j<<"].height is "<<P[j].height<<". break!"<<endl;
				m--;	
			//	cout<<"m is "<<m<<endl;
				break;
			}else
			{
		//		cout << "pi's height: "<<P[i].height<<"   pj's height: "<<P[j].height<<endl;
			
			}
			if(j == i){
				//cout<<" bingo!!!!!!!!!"<<endl;
			}
		}
	}
//	cout << "count:"<<count<<endl;
	//cout<<endl;
	cout<<m<<endl;
}<strong>
</strong>


题目给的实例测试结果是对的,但为应对如
4
1 80 111
2 70 101
3 70 102
4 60 70
会被认成只能叠3个的问题,第一遍排序的if语句加了相等情况的额外判定,体重相等的时候比较身高,身高高的在前,事先排好。这是因为后续的比较纯粹看排后边的人身高是否超越自己,过于理想化。(另一种思路,在比身高的时候再加上体重判定,比如体重相等之类的,不过太复杂了,不如前一种方法好)



可能出现问题的还有,第一次是排序,而第二次纯粹是根据条件去除不要的结果,计数器m自减。所以,有没有可能是因为没删除不要的数据导致的错误呢?按理说也不应该,i是递增的,前边的数据不行就是不行了,也不会再比较到,按理说不应该。

这个方法目前还没通过OJ的测试,OJ测试用例548个输入,期待的结果是20,自己的程序输出只有9。复制测试用例,自己本地输出是这样,OJ有时候能显示输出9,有时候显示空。

笔记本字太小,状态不太好,明天继续研究。



===============================================================================================================================
为防止排序错误,抄了一个选择排序算法,出了第二版

#include<iostream>
using namespace std;
struct person{
	unsigned int id;
	unsigned int weight;
	unsigned int height;
};
int main(){
	int count = 0;
	int min = 0;
	cin>>count;
	struct person P[count];
	int i = 0;
	for(i = 0; i < count; i++)
	{
		cin>>P[i].id>>P[i].weight>>P[i].height;
	}

	cout <<"before weight swap!!!!!!!!!!!!!!!!!!!!!"<<endl;
	for(int i = 0;i < count;i++)
	{
		cout << "id:"<<P[i].id<<" weight:"<<P[i].weight<<" height:"<<P[i].height<<endl;
	}	
	//第一次排序,体重从大到小
	unsigned int tmpId,tmpWeight,tmpHeight;
	for(i = 0;i < count - 1;i++)
	{
		min = i;//set the min val
		for(int j = i + 1;j < count;j++)
		{
			if(
//算身高的
			(P[min].weight < P[j].weight)||
			((P[min].weight == P[j].weight)&&
			(P[min].height < P[j].height))
//简便的只算体重的
//			(P[min].weight < P[j].weight)
			)
			{
				min = j;
			}
		}
		if(min != i)
		{

				tmpId = P[i].id;
				tmpWeight = P[i].weight;
				tmpHeight = P[i].height;
				P[i].id = P[min].id;
				P[i].weight = P[min].weight;
				P[i].height = P[min].height;
				P[min].id = tmpId;
				P[min].weight = tmpWeight;
				P[min].height = tmpHeight;
		}

	}
	cout <<"after weight swap!!!!!!!!!!!!!!!!!!!!!"<<endl;
	for(int i = 0;i < count;i++)
	{
		cout << "id:"<<P[i].id<<" weight:"<<P[i].weight<<" height:"<<P[i].height<<endl;
	}	
//	cout << "count : "<< count << endl;
	//排除身高顺序不符合的
	//不能片面删除所有身高不按降序排列的
	//因为还有同体重下的身高降序,可能出现过度减
	//要考虑体重因素,前提是体重不相同
	unsigned int m = count;//最终结果m,罗汉层数
	for(i = 0;i < count;i++)
	{
		//cout <<"P[i = "<<i<<"].height is "<<P[i].height;
		for(int j = count - 1;j >= i;j--)
		{
	//		cout << " j:"<<j<<endl;
			if(P[i].height < P[j].height)
			{
			//	cout << "pi's height: "<<P[i].height<<"   pj's height: "<<P[j].height<<endl;
				//cout << endl << "P[j = "<<j<<"].height is "<<P[j].height<<". break!"<<endl;
				m--;	
			//	cout<<"m is "<<m<<endl;
				break;
			}else
			{
		//		cout << "pi's height: "<<P[i].height<<"   pj's height: "<<P[j].height<<endl;
			
			}
			if(j == i){
				//cout<<" bingo!!!!!!!!!"<<endl;
			}
		}
	}
//	cout << "count:"<<count<<endl;
	//cout<<endl;
	cout<<m<<endl;
}

把五百多个数值的用例输进去,结局还是9。
输出检查也证实,排序无错,错在最后的计算m上了

m的计算是初始化为count,看身高降序,看到一个后边比自己高的就排除掉一个,所以过度减了。20变9
举个反例:
体重 身高
89 101
88 100
87 105
87 100
87 99
86 80
这里边因为有87-105的存在,89-101与88-100会被认为无效,结果是4。
实际上,最优的方法是排除87-101,这样结果会是5。

这个傻瓜错误的根源也是没充分考虑体重(第一条件)相同情况下身高(第二条件)的排序与相应的考虑。

 ps:因为输出要的东西少,id也是可以 不要的参数,此处保留方便调试。

===============================================================================================================================
现在的减法思路是这样:
遍历,i和j比较
if(P[i].height<P[j].height)
{
//在此前提下还要看P[j].weight,找到和P[j].weight同weight的,看看有没有P[k].weight == P[j].weight 并且P[k].height <= P[i].height(别丢了等于号),哪怕有一个,m就不用减1了!可以把从j到k-1对应的都扔掉
//但是,此情况代表j不能用了,必须删除,不然j 留下来会干扰结果,因为当遍历到 j时,j不记得他不应该存在,通过对比后边的height值,可能认为自己应该存在。
//另外,并没有给height做哈希表之类的映射,没法通过指定的height值找j-1到k对应的数据,只能原地自增操作tmp = j + 1,然后再比较一下P[tmp].weight和P[j].weight,相同时再看height,比较繁琐。

}



===============================================================================================================================
上边的策略还是有问题,举一反例:
89 102 
89 101
87 107
87 106
87 105
87 101
通过上边的策略,遇87-101,就把87-107、87-106、87-10全删了,结果是3,而如果删89-102与89-101,结果会是4。

那么绑定呢?89绑一坨,87绑一坨,但是一坨内有高有低还是很难权衡,甚至还可能包括与88和85们的互相影响。


总管全局,让我取舍的话,我觉得还是尽量留身高大的,因为好几百个甚至上千个数呢。但是这个东西靠政策是不行的,必须放之四海皆可, 比如前一例,留87-105会损失两个呢,也不是最优。















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值