2019-02-26-University Entrace Examination -ZOJ1023-稳定婚姻算法(变式)

ZOJ-1023-University Entrace Examination

Problem Description

There is a fierce competition among high-school graduates in Iran to pass the centralized nationwide university entrance examination. Ministry of Science, Research, and Technology has set up the Education Evaluation Organization (EEO) to take care of all aspects of this big exam. This year the EEO managed to select some 150,000 students to enter universities out of 1.4 million high school graduates participated in a tough 4.5 hours multiple-choice exam. This annual event is usually preceded by a multi-billion Rial business offering preparatory courses to enthusiastic students. A few weeks after the big exam day, each participant receives a score sheet, and a list of Field-Department-University (FDU), displaying each field of study in the universities锟斤拷 departments (e.g., the Software Engineering field of Computer Engineering department at Sharif University of Technology) along with their capacity for that year. The eligible participants (those who have scored enough to be allowed to declare their FDU priorities) fill out a priority indication form, and declare the FDUs they like to enter, in the order of their preference. The EEO processes the forms, and considering the total score, the participant锟斤拷s FDU priority list, and some other selection rules, enters the accepted participants锟斤拷 names in the list of each FDU, until all capacities are exhausted. Those who are not entered in a list are considered failed and may try again next year. Each accepted participant锟斤拷s name may be entered in only one list.

One of the interesting selection rules is to persuade participants to enter universities in the vicinity of their home towns. This is to help reduce the number of requests for staying in the university dormitories.
The selection process is so complex and so sensitive to many, that EEO has decided to hire the very best programmers in Iran to design a new selection algorithm and write a completely new program for what they have been doing for years. ACM programming contest is where these programmers can be found.

There are N students S1 to SN , and M items F1 to FM , each representing one of the FDUs. There are also a number of geographic regions. For each participant, the total score, the geographic region where his/her high school diploma was awarded, and a priority list of his/her wanted FDUs are available. For each FDU, the geographic region where the corresponding university is located, and its capacity for that year is recorded.

Write a program to compute the list of accepted students with the FDU they can enter to, given the above list of input data. Your program must abide with the following rules:

1. (Local student selection rule) Suppose two students A and B have both selected F in their priority lists and F is in region R. Also suppose that score of A is greater than B's score. Then, if B is from region R (local) and A is from other regions (non-local), and B's score is greater than 70% of A's score, then B has priority over A to enter F. In all other cases A has priority over B to enter F.

2. (Fairness rule) Students should be treated according to their priority list of FDUs. That is, an accepted student will be accepted to the first possible FDU he/she can enter.

Note: We assume that scores are all different integer values.


Input

The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains N (1 <= N <= 150) and M (1 <= M <= 50) followed by N lines, each for one student. The format of these lines is Ri, Mi, K, Fi1, 锟斤拷, FiK in this order. In this line, that is for student i, Ri is his/her region number, Mi is his/her score in the entrance exam, K is the number of FDUs in his/her priority list (0 <= K <= M), and his/her priority list containing the FDU numbers in order of interest. Then there are M lines, one for each FDU. Each line contains Ri, and Ci in that order, which respectively is region number of Fi (the ith FDU) and the capacity of Fi. Note that region numbers are arbitrary integers.

Output

Outputs for different test cases are separated by exactly one blank line. For each test case, you should write N lines, one for each of the N students. If student i has been accepted to FDU Fj, then ith line should contain j, and not accepted, if that student has not been accepted in any FDU of his/her interest.


Sample Input

1
9 2
1 100 2 1 2
2 80 2 2 1
1 90 1 1
2 40 1 2
2 50 1 1
1 60 1 2
2 75 1 1
1 95 1 1
2 30 1 2
1 3
2 4

Sample Output

1
2
1
2
not accepted
2
not accepted
1
2

问题简述

题意:对于给定的n个学生和m所学校,已知学生i的k个期望学校和排名,每个学生的地理位置和分数,以及每所学校的容纳上限,试在满足条件下使其形成稳定匹配。

条件

1.假设学生a,b都有期望学校x,对于x而言,如果a来自x的区域,b不来自x的区域,且a的分数大于70%的b的分数,那么x更倾向于选择a;在其他情况下,x总是选择分数高的学生。

2.一个被录取的学生应该进入到他第一个可能进入的学校。(按优先列表来选择

难点:类似于稳定婚姻算法,但是学生(男生)可能匹配不到学校学校(女生)可能匹配多个学生

所以循环终止条件应改为:任何一个学生或者有匹配,或者已经对所有倾向列表上的学校表白过

条目检索:稳定婚姻算法

输入输出

输入:无难度,t组数据,n个学生,m所学校,n行学生信息(所在区域,分数,期望学校数k,k所期望学校编号),m行学校信息(所在区域,容纳上限)

输出:无难度

使用模板(稳定婚姻算法)

struct Gale_Shapley{
	static const int N=60;
	int n;
	int fg;
	int woman[N][N];        //第i个girl对编号j的boy的好感排位 
	int man[N][N];          //第i个boy第j喜欢的girl 
	int man_match[N],woman_match[N];    //已匹配的男女 
	int p[N];               //第i个boy已经表白的人数 
	void solve(){
		for(int i=0;i<N;i++)p[i]=1;//初始化每个男生表白1次
		memset(man_match,0,sizeof(man_match));
		memset(woman_match,0,sizeof(woman_match));
		fg=true;
        //fg标记当前是否还有人没有匹配
		while(fg){
			fg=false;
			for(int i=1;i<=n;i++){//男生i进行表白
				if(!man_match[i]){//如果没有匹配
					int t=man[i][p[i]++];//男生向下一个倾慕对象表白
					if(!woman_match[t]){//如果女生没有匹配,直接配对
						man_match[i]=t;
						woman_match[t]=i;
					}else if(woman[t][woman_match[t]]>woman[t][i]){
                        //如果女生觉得这个男生比自己现在的更好
						man_match[woman_match[t]]=0;    //抛弃之前的
						man_match[i]=t;
						woman_match[t]=i;
					}
					fg=true;
				}
			}
		}
	}
}T;

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200
using namespace std;
typedef struct student{
	int id;            //学生编号 
	int area;          //所在区域 
	int score;         //分数 
	int k;             //中意学校数 
}student;
typedef struct school{
	int area;          //区域 
	int v;             //容量 
}school;
typedef struct matchs{
	int cnt;           //容纳学生数
	int match[N];      //列表
}matchs;
student stu[N];        //学生信息
school sch[N];         //学校信息
matchs fmat[N];        //学校匹配的学生数,和学生列表
int mmat[N];           //学生匹配的学校
int man_match[N][N];   //学生i第j期望的学校
int woman_match[N][N]; //学校i对于学生j的倾向度
int vis[N];            //i是否已经全部表白过 
int p[N];              //当前i要向p[i]表白 
int n,m;               //n学生,m学校 
int rr;                //当前区域 

bool cmp_a(student a,student b){      //比较函数a
	if(a.area==rr&&b.area!=rr){
		if(fabs(a.score-0.7*b.score)<1e-6)return 0;
		else return a.score>0.7*b.score;
	}else if(a.area!=rr&&b.area==rr){
		if(fabs(b.score-0.7*a.score)<1e-6)return 1;
		else return b.score<0.7*a.score;
	}else{
		return a.score>b.score;
	}
}
bool cmp_b(student a,student b){      //比较函数b
	return a.id<b.id;
}

void read(){
	scanf("%d%d",&n,&m);
	int ri,mi,ki,ch;
	memset(man_match,0,sizeof(man_match));
	memset(woman_match,0,sizeof(woman_match));
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&ri,&mi,&ki);
		stu[i].id=i;
		stu[i].area=ri;
		stu[i].k=ki;
		stu[i].score=mi;
		for(int j=1;j<=ki;j++){
			scanf("%d",&ch);
			man_match[i][j]=ch;       //男生i第j喜欢的女生是ch 
		}
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&sch[i].area,&sch[i].v);
	}
}
void getRank(){
	for(int i=1;i<=m;i++){
		rr=sch[i].area;
		sort(stu+1,stu+n+1,cmp_a);        //把学生按照学校i的区域排序
		for(int j=1;j<=n;j++){
			woman_match[i][stu[j].id]=j;  //学校i对于学生stu[j].id的倾向度为j
		}
	}
	sort(stu+1,stu+n+1,cmp_b);            //按照学生编号排序,即回归原状
}
void GS(){
	bool fg=1;
	memset(mmat,0,sizeof(mmat));
	for(int i=1;i<=n;i++){
		p[i]=1;
		vis[i]=0;
	}
	for(int i=1;i<=m;i++){
		fmat[i].cnt=0;
	}
	while(fg){
		fg=0;
		for(int i=1;i<=n;i++){            //每个学生进行表白 
			while(!mmat[i]&&!vis[i]){     //直到i匹配到学校,或者再也不能匹配到学校停止
				fg=1;
				if(p[i]>stu[i].k){        //如果i现在已经对所有倾向的学校表白过,则标记
					vis[i]=1;
					break;
				}
				int u=man_match[i][p[i]++];     //i当前想要表白的学校
				if(fmat[u].cnt<sch[u].v){       //如果u学校还有空余,表白成功 
					fmat[u].match[++fmat[u].cnt]=i;
					mmat[i]=u;
				}else if(fmat[u].cnt==sch[u].v){//如果u学校当前没有空余
					int worstrank=0;
					int worstid;
					for(int j=1;j<=fmat[u].cnt;j++){//找到u学校当前列表中最不喜欢的学生
						if(worstrank<woman_match[u][fmat[u].match[j]]){
							worstrank=woman_match[u][fmat[u].match[j]];
							worstid=j;
						}
					}
					if(worstrank>woman_match[u][i]){//如果i比最差的更好,则取代位置
                        //下面两行不能互换!!
                        //易错点
						mmat[fmat[u].match[worstid]]=0;
						fmat[u].match[worstid]=i;
						mmat[i]=u;
					}
				}
			}
		}
	}
	
}
int main(){
	int cases;
	scanf("%d",&cases);
	while(cases--){
		read();
		getRank();
		GS();
		for(int i=1;i<=n;i++){
			if(vis[i])printf("not accepted\n");
			else printf("%d\n",mmat[i]);
		}
		if(cases)printf("\n");
	}
	return 0;
}

参考链接

https://blog.csdn.net/secfly/article/details/50768559

https://blog.csdn.net/RaAlGhul/article/details/50686211

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值