题目链接:
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、最后再来一次快排,找出最佳
最后放一个成绩截图,最后快排是正确的,但是我好菜