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