202012-2 期末预测之最佳阈值

题目链接:

http://118.190.20.162/view.page?gpid=T122(就不多加赘述了)

思路

一、暴力法:两个for循环,很显然这是最简单的一种,但是超时了 ,时间复杂度O(m2

#include <iostream>
using namespace std;
int y[100000];//安全指数 
int result[100000];//挂科情况 
int main()
{
	int m;
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&y[i],&result[i]);
	}
	int best=0; //最佳阈值 
	int i=0;
	int maxnum=0;
	while(i<m)
	{	
		int num=0;//记录预测成功的次数 
		int predict;
		int now=y[i];//当前所选取的阈值 
		for(int j=0;j<m;j++)
		{
			if(y[j]<now) predict=0;
			else predict=1;
			if(predict==result[j]) num++;//计算预测成功次数 
			if(num>maxnum||num==maxnum) {//判断是不是最大的,进行更新 
				maxnum=num;
				if(now>best||now>best) best=now;
			}
		}
		i++;
	}
	printf("%d",best);
} 

而且最要命的是,我感觉代码可能也有问题,但是由于没有错误提示,我也无从考证,先一步步向下走吧
(最开始我想将所有的cin,cout换成scanf和printf想着减少一点时间,或许可以糊弄过去,但是很显然效果不大)
后来修改一下,找出自己代码错误的地方

while(i<m)
	{	
		int num=0;//记录预测成功的次数 
		int predict;
		int now=y[i];//当前所选取的阈值 
		for(int j=0;j<m;j++)
		{
			if(y[j]<now) predict=0;
			else predict=1;
			if(predict==result[j]) num++;//计算预测成功次数 
			if(num>maxnum) {//判断是不是最大的,进行更新 
				maxnum=num;
				best=now;
			}
			else if(num==maxnum){
				if(best<now) best=now;
			}
		}
		i++;
	}

二、没有理解之下,写的快排,其实时间复杂度还是O(m2),但还是把代码贴出来

#include <iostream>
#include<algorithm>
using namespace std;
struct student{
	int y;
	int result;
	int num;
};
bool cmp(student a,student b){
	return a.y<b.y;
}
bool cmp1(student a,student b){
	if(a.num<b.num)	return true;
	else if(a.num==b.num){
		if(a.y<b.y) return true;
		else return false;
	}
	else return false;
}
int main(){
	int m;
	cin>>m;
	student stu[m];
	for(int i=0;i<m;i++){
		cin>>stu[i].y>>stu[i].result;
		stu[i].num=0;
	} 
	sort(stu, stu+m,cmp);//快排 ,由小到大 
	for(int i=0;i<m;i++){
		for(int j=0;j<i;j++)	//y<now,0
		{
			if(stu[i-1].y!=stu[i].y){
				if(stu[j].result==0) stu[i].num++;	
			}
			else if(stu[i-1].y==stu[i].y){
				if(stu[j].result==1) stu[i].num++;
			}
		}
		for(int j=i;j<m;j++){
			if(stu[j].result==1) stu[i].num++;
		}
	} 
	sort(stu,stu+m,cmp1);
	cout<<stu[m-1].y;
} 

三、快排
先对输入进行快排,这样或许少了计算predict的时间
为了快排方便这里我选择引入结构体,在这里顺带复习一下结构体快排,好久没写代码都忘记了

#include <iostream>
#include<algorithm>
using namespace std;
struct student{
	int y;
	int result;
	int num;
};
bool cmp(student a,student b){
	return a.y<b.y;
}
bool cmp1(student a,student b){
	if(a.num ==b.num )
		return a.y<b.y;
	else
		return a.num < b.num; 

	if(a.num<b.num)	return true;
	else if(a.num==b.num){
		if(a.y<b.y) return true;
	}
	else return false;
}
int main(){
	int m;
	cin>>m;
	student stu[m];
	int flag0[m];
	int flag1[m];
	for(int i=0;i<m;i++){
		cin>>stu[i].y>>stu[i].result;
		flag0[i]=0;
		flag1[i]=0;
		stu[i].num=0;
	} 
	sort(stu, stu+m,cmp);//快排 ,由小到大 
	//先把第一个算出来
	for(int i=0;i<m;i++)
	{
		if(stu[i].result==1) flag1[0]++;//第一个只有1 
	} 
	int j=1;//i是计算的,j是每个要算的阈值 
	//现在开始计算小于当前并且result=0的情况 
	//往后推,前面都是0,后面的也一定是0 
	int temp0=0; 
	int i=0;
	while(j<m){
		//其实最开始一样的话,反正y都一样,那么计算的结果也是一样的,可以直接跳过
		if(stu[j].y==stu[i].y) {
			j++;
			continue;
		}
		while(i<j){
			if(stu[i].result==0){
				temp0++; 
			}
			i++;
		}
		//if(stu[j-1].y==stu[j].y) i=j-1;有可能前面有很多一样的,所以这样不行 
		flag0[j]=temp0;
		j++;
	} 
	//开始计算大的 
	j=1;
	//往回推,后面的是1,往前走也是1
	int temp1=0; 
	for(int i=0;i<m;i++){
		if(stu[m-1-i].result==1){
			temp1++;
		}
		flag1[m-1-i]=temp1;
	}
	for(int k=0;k<m;k++)
	{
		stu[k].num=flag0[k]+flag1[k];
	}
	sort(stu,stu+m,cmp1);
	cout<<stu[m-1].y;
	return 0;
} 

(首先要理解,其实也就是计算比自己小的0的个数,以及大于等于自己1的个数)
其实关于快排我理解了好久好久,借鉴了一位大佬的写法,还给我大概讲了以下感动,大概步骤分为以下几步吧。
1、快排,输入y,由小到大
2、计算比自己小的0的个数,需要注意的是,其实当前的里面一定包含前面计算过的。如果遇到相等的,直接跳过就好,但是记得j++,但是i的位置不变。下一次循环,从上一次结尾i开始
3、计算比自己大的或者等于1的个数,这个就要简单很多。后面是1,往前走也是1,所以只要不断判断当前是否是1就行
4、最后再来一次快排,找出最佳
最后放一个成绩截图,最后快排是正确的,但是我好菜
在这里插入图片描述

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页