题意:
根据学生的成绩和排名,根据学校的招生情况,确定最终的招生结果。
输入N,M,K,代表N个学生,M个学校,每个学生有K种志愿(可以相同)
接下来的一行输入M个整数,代表这M个学校的最多录取人数
接下来的N行,每一行输入2+K个数,分别代表学生的GE(高考成绩)、GI(面试成绩)、K个志愿
录取规则:
(1)根据学生的GE和GI平均成绩从高到低排名,相等则继续比较GE,GE如果也相等则两个学生排名相同;
(2)根据排名名单,依次看学生的志愿学校;
(3)如果当前志愿学校录取人数未满则录取该生;
(4)如果两学生排名一样,且申请的是同一所学校,那么学校即使录取名额超限,也必须录取他们。

于是:可能有学生所有志愿均被刷,也可能有学校录取不到学生。

思路很简单,用两个结构体存取school和student的信息,并按照录取规则进行依次录取。

#include<stdio.h>
#include<stdlib.h>

typedef struct{
    int total; // 需要录取的人数
    int already; // 当前已录取的人数
    int select[100]; // 录取的学生
}School; // 学校信息

typedef struct{
    float GE,GI,final;
    int id;
    int choice[6]; // 志愿
}Student; // 学生信息

int cmp(const void *a,const void *b) // student根据成绩排序
{
    Student * x = (Student*)a;
    Student * y = (Student*)b;
    if(x->final != y->final)
        return y->final*10 - x->final*10;
    else
        return y->GE*10 -x->GE*10;
}
int cmp2(const void *a,const void *b) // school录取学生编号升序排序
{
    int *x = (int *)a;
    int *y = (int *)b;
    return *x-*y;
}
int main()
{
    int N,M,K;
    scanf("%d %d %d",&N,&M,&K);
    School school[M];
    Student  student[N],temp[N];
    int i,j;
    for(i = 0;i<M;i++)
    {
        scanf("%d",&school[i].total);
        school[i].already = 0;
        for(j = 0;j<100;j++)
            school[i].select[j] = 99999;
    }
    for(i = 0;i<N;i++)
    {
        scanf("%f %f",&student[i].GE,&student[i].GI);
        student[i].final = (student[i].GE + student[i].GI)/2;
        student[i].id = i;
        for(j = 0;j<K;j++)
            scanf("%d",&student[i].choice[j]);
        for(;j<6;j++)
            student[i].choice[j] = -1;
    }
    // 在排序前将原始student信息保存在temp,用于扩招时使用(因为排序后的student下标和id不一致)
    for(i = 0;i<N;i++)
    {
        temp[i].final = student[i].final;
        temp[i].GE = student[i].GE;
    }
    qsort(student,N,sizeof(Student),cmp); // 学生按成绩排序

    //依次遍历每个学生的每个志愿
    for(i = 0;i<N;i++)
    {
        for(j = 0;j<K;j++)
        {
            int want = student[i].choice[j]; // want为当前学生当前志愿的学校编号
            if(school[want].already<school[want].total) // 如果该校还未录取完毕
            {
                school[want].select[school[want].already] = student[i].id;
                school[want].already++;
                break;
            }
            else // 考虑是否扩招
            {
                //already-1下标的必是该校最后一个录进来的学生,与他比较即可。
                if(temp[school[want].select[school[want].already-1]].final == student[i].final && temp[school[want].select[school[want].already-1]].GE == student[i].GE) // 如果GE和GI均相同则扩招
                {
                    school[want].select[school[want].already] = student[i].id;
                    school[want].already ++;
                    break;
                }
            }
        }
    }
    for(i = 0;i<M;i++) // 对每个学校的录取人序号升序排列
        qsort(school[i].select,school[i].already,sizeof(int),cmp2);
    for(i = 0;i<M;i++) // 输出学校录取情况
    {
        if(!school[i].already) // 没录取到学生
            printf("\n");
        else
        {
            for(j = 0;j<school[i].already;j++)
            {
                if(j == school[i].already-1)
                    printf("%d\n",school[i].select[j]);
                else
                    printf("%d ",school[i].select[j]);
            }
        }
    }
    return 0;
}