排序题型总结
pat的的排序题一般是对成绩,总分的排名,还有少数对时间长短以及财富进行了排名。
这类题目通常先定义一个结构体来保存学生等的ID、成绩、总分、名次等信息。
1.如:pat B1015
struct student{
char ID[10];
int de, cai, sum;
int flag;
}stu[10010];
对于排序来说pat中经常用sort函数进行排序,sort(首迭代器, 尾迭代器,cmp), 这里的cmp函数是自己定义的优先级操作,然后sort函数根据cmp指定的优先级排序。如:
bool cmp(student a, student b)
{
if(a.flag != b.flag)
return a.flag < b.flag;
else if(a.sum != b.sum)
return a.sum > b.sum;
else if(a.de != b.de)
return a.de > b.de;
else return strcmp(a.ID, b.ID) < 0;
}
注意一般的名字、ID都是用strcmp函数进行比较,不要直接进行比较:如a.ID < b.ID。strcmp函数在cstring头文件中。strcmp函数小于0时,说明名字是按字典序来从小到大来排列,等于0时则两个字符串长度,各个字符均相等。如:
strcmp(“ab”, “a”) > 0, 因为“ab”长度大于“a”.
strcmp(“ab”, “ac”)<0, 因为第一个字符相同就会比较第二个。
除此之外struct中通常还加入一些bool变量以及其他类型的变量来表示是否通过以及类别等。如这里这道题要将考生分成几类,然后按类别排序。这样我们就可以通过设置一个flag变量来存放考生的类别。
2.再来看看另外一道题目:pat1016
这里给出24个小时每个时段的电话费,并给出N个通话记录,然后对每个人的有效通话记录进行资费计算,有效通话是指同一用户能够配对的所有on-line,off-line,而且对应的on-line,off-line中间不能出现其他的on-line,off-line记录。输出要求:按名字字典序大小输出所有有效通话及总话费.
所以这里的可以用一个变量来表示on-line,off-line。将status置为true表示on-line,false表示off-line.
struct Record{
int month, dd, hh, mm;
char name[25];
bool status;
}rec[1010], temp;
那这里的on-line, off-line怎么配对又怎么表示呢?
while(on < n)
{
int needPrint = 0;
next = on;
while(next < n && strcmp(rec[on].name, rec[next].name) == 0)
{
if(needPrint == 0 && rec[next].status == true)
needPrint = 1;
else if(needPrint == 1 && rec[next].status == false)
needPrint = 2;
next++;
}
if(needPrint < 2)
{
on = next;
continue;
}
int AllMoney = 0;
printf("%s %02d\n", rec[on].name, rec[on].month);
while(on < next)
{
while(on < next-1 && !(rec[on].status == true && rec[on+1].status == false))
on++;//直至找到连续的on-line和off-line
off = on+1;//off是on的下一个
if(off == next)
{
on = next;
break;
}//已经输出所有的有效对
printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
int time = 0, money = 0;
get_ans(on, off, time, money);
printf("%d $%.2f\n", time, money/100.0);
AllMoney += money;
on = off+1;
}
printf("Total amount: $%.2f\n", AllMoney/100.0);
}
我们用一个变量needprint来记录表示on-line, off-line.当on-line时将needprint置为1,而当off-line时则置为2。如果最终needprint小于2,则说明不存在有效配对,就可以跳出循环,进入下一次循环。然后输出有效对。
3. 排序后输出某个区间的对象:
输出给定年龄段的人:
for(int j = 0; j < num; j++)
{
if(valid[j].age >= min_age && valid[j].age <= max_age)
{
if(count == number)
break;
printf("%s %d %d\n", valid[j].name, valid[j].age, valid[j].worth);
count++;
}
4. 分情况判断,这个时候我们需要单独用一个变量来存储,以判断各种情况。如pat A1075:
for(int i = 0; i < subm; i++)
{
scanf("%d%d%d", &u_id, &p_id, &obtain_score);
if(obtain_score != -1)
stu[u_id].flag = true;
if(obtain_score == -1 && stu[u_id].score[p_id] == -1)
stu[u_id].score[p_id] = 0;
if(obtain_score == full[p_id] && stu[u_id].score[p_id] < full[p_id])
stu[u_id].solve++;
if(obtain_score > stu[u_id].score[p_id])
stu[u_id].score[p_id] = obtain_score;
}
我们这里就用一个obtain_score先来判断,最后如果大于最大分数就将其赋给这个学生。还有pat A1012:
这里比较学生各科的名次,然后要输出这个学生的最高名次:所以我们单独用一个Rank数组来存储各个科目的名次,最后找出最高名次, 这里也给出了名次的一般求法:
int Rank[1000000][4] = {0};
for(now = 0; now < 4; now++)
{
sort(stu, stu+n, cmp);
Rank[stu[0].id][now] = 1;
for(int i = 1; i < n; i++)
{
if(stu[i].grage[now] == stu[i-1].grage[now])
Rank[stu[i].id][now] = Rank[stu[i-1].id][now];
else
Rank[stu[i].id][now] = i+1;
}//求名次
}
5. 在某个时间段进出的车辆:
for(int i = 0; i < k; i++)
{
scanf("%d:%d:%d", &hh, &mm, &ss);
int time = timeToInt(hh, mm, ss);
while(now < num && valid[now].time <= time)
{
if(!strcmp(valid[now].status, "in"))
numCar++;
else
numCar--;
now++;
}
printf("%d\n", numCar);
}
总结: 一般来说先定义一个结构体,再根据题目给定的排序要求来定义cmp函数。对于一些比较复杂的情况分析我们可以单独用一个变量来存储然后依次分析。