ACM入门:第s名的小红
前几天的大一新生赛自己也跟着做了做,顺便测测后台数据有没有bug,这是一道排序题,题目如下:
Problem Description
Input
Output
Sample Input
5 1 2 3 4 5
Sample Output
2
题目如上,看到题的第一反应,毫无疑问的桶排。事实上准备出来的标程也是如此,思路如下:
由于n的范围为0~1e6,所以开一个长度为一百万的一维数组(初始化为0),数组下标与出现过的数字相对应,数字每出现过一次,对应的数组元素值重置为1,循环输入完成后,另开一圈循环,从0开始,直到找到第二个数组元素对应值为1的元素,输出其下标,即为所求。
代码如下:
#include<stdio.h>
int main()
{
int n;
while (~scanf("%d",&n))
{
int a[1000000]={0};
for(int i=0;i<n;i++)
{
int k;
scanf("%d",&k);
a[k]=1;
}
int flag=0;
for(int i=0;i<1000000;i++)
{
if(a[i]!=0)
flag++;
if(flag==2)
{
printf("%d\n",i);
break;
}
}
if(flag!=2)
printf("No find\n");
}
}
结果自然是ac了,然而缺点是内存开的太大了。so。。。小开了一波脑洞,思路如下:
既然是只输出第二位元素,那么只进行简单的排序,输出第二位不就好了,那么利用冒泡排序的思想,只让两个元素沉底之后输出第二个不就好了,然而这个算法有一个非常明显的bug,就是对于相同元素的情况处理,假设有两个或者两个以上的最小元素沉底的话,如:5 1 1 2 3 4 ,那么最小的数有两个即两个1,那么循环会执行两次外层循环,结果为 2 3 4 1 1,那么结果很明显是错误的。那么只要在判断与上一个已经沉底的元素相同的话,改变i值,执行i--,使得外层循环强行增加一次。后来这种想法被舍弃了,原因有两个,第一,数组下标实在是太难计算了,而且下标计算出错改错也很困难。第二,如果是特殊数据的话,例如 5 1 1 1 1 2,那么时间复杂度就会变成O(n²),所以并不可取(实际上是因为数组下标算烦了)。。。
不过在算数组下标的时间里,又诞生了一种想法,既然是找到第二小的元素,那么只要找到最小的元素,除去最小的元素以外的元素里剩下的部分,其中最小的元素不就是第二小的了么,而且这样实现的话,对于元素除重的问题也很好解决。不过还是要从同到尾遍历两次数组,那么是否可以将其塞到一层循环里呢(输入完数据后不再经历循环),答案当然是可以的(如果我没实现出来就不在文里提了。。。)思路如下:
在输入一个数组元素后用两个变量记录下当前扫过的最小值和仅次于最小值的值,遍历数组后直接输出就好。代码如下:
#include<stdio.h>
int main()
{
int a[10005];
int n;
while (~scanf("%d",&n))
{
int flag=0;
int flag2=0;
int min1=10001;
int min2=10001;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
if(a[i]<min1)
{
min2=min1;
min1=a[i];
}
else if(a[i]!=min1&&a[i]<min2)
min2=a[i];
}
if(min2==10001)
printf("No find\n");
else
printf("%d\n",min2);
}
}
这样的话内存就小了很多,相比桶排的实现,内存上还是存在一定程度上的优化的,而且如果是桶排,局限性也得到了解决(题目限制数据输入不超过1e6如果是1e15这样的数据范围,一维数组的内存申请就会出错)
但是这是求第二小的元素,如果是第n小呢,即便我可以写到第n个min,也不可能写出那么多的else if()啊。。。所以我开始继续改良我的“冒泡版”算法。
鉴于之前的遇到重复元素的处理既费时又费力。。。所以新的处理办法思路如下:
对于存在重复元素的数据,如果重复的元素本身并不是第二小,或者第一小,不用考虑,如果是,那么设置条件,当前的元素必须不等于已经沉底的元素,而且小于下一个元素的时候才执行元素互换。代码如下:
#include<stdio.h>
int main()
{
int n;
while (~scanf("%d",&n))
{
int a[10000];
int flag=-1;
int j;
int flag2=0;
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
if(flag2||a[i]!=a[0])
flag2=1;
}
for(int i=0; i<2; i++)
{
for(j=0; j<n-1-i; j++)
if((a[j]<a[j+1]||a[j+1]<=flag)&&a[j]>flag)
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
flag=a[j];
}
if(flag2)
printf("%d\n",a[n-2]);
else
printf("No find\n");
}
}
ac...算是把一开始脑洞搬到电脑上了。。。然而。。。刚填完一个脑洞,又开了一个:能不能实现它的推广呢,即题目那样,可以任意改变第几小。继续想需要改动的地方,想了一圈。唯一的难点是No find,因为不能在输入的时候直接判定有几个不同元素了,这个问题困扰了好一阵,大致思路还是想塞到输入的那层for里,但是直到现在也没用这种方法实现。所以转了一种思路,把这个判定放到别的地方去,思路如下:
每次外层循环结束,即有元素沉底后,判断这个刚刚沉底的元素和倒数第二个沉底的元素的关系,正常情况下,应该是刚刚沉底的元素大于倒数第二个沉底的元素,而非正常情况下,也就是No find时,这个刚刚沉底的元素一定会小于等于倒数第二个沉底的元素。代码如下:
#define s 2
int main()
{
int n;
while (~scanf("%d",&n))
{
int a[10000];
int flag=-1;
int flag2=0;
int flag3=0;
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
for(int i=0; i<s; i++)
{
for(j=0; j<n-1-i; j++)
{
if((a[j]<a[j+1]||a[j+1]<=flag)&&a[j]>flag)
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
if(a[j]<=flag)
{
flag3=1;
break;
}
flag=a[j];
}
if(!flag3)
printf("%d\n",a[n-s]);
else
printf("No find\n");
}
}
比赛的后台并没有这样的测试样例,so。。。没有结果返回了,不过自己把想到的数据都测了,结果无误。
至此,脑洞已全部填完。。。
ACM入门:第s名的小红的更多相关文章
- 大牛对ACM入门菜鸟的一些话
首先就是我为什么要写这么一篇日志.原因很简单,就是因为前几天有个想起步做ACM人很诚恳的问我该如何入门.其实就现在而言,我并不是很想和人再去讨论这样的话题,特别是当我发现我有很多的东西要学的时候,我实 ...
- eclipse工程名出现小红叉的解决办法
前提是eclipse工程中每个子文件都没错,工程名上却显示了小红叉. 打开[Window]->[Show View]->[General]->[Problems],看看Problem ...
- ACM入门步骤(一)
一般的入门顺序: 0. C语言的基本语法(或者直接开C++也行,当一个java选手可能会更受欢迎,并且以后工作好找,但是难度有点大),[参考书籍:刘汝佳的<算法竞赛入门经典>,C++入门可 ...
- ACM入门指南
本文已经转移到了:http://harryguo.me/2015/11/03/ACM-%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/ 什么是ACM? 想必打开这篇博客的人已 ...
- acm入门 杭电1001题 有关溢出的考虑
最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...
- ACM 入门计划
acm 本文由swellspirit贡献 ACM • I can accept failure. but I can't accept not trying. Life is often compar ...
- ACM入门之OJ~
所谓OJ,顾名思义Online Judge,一个用户提交的程序在Online Judge系统下执行时将受到比较严格的限制,包括运行时间限制,内存使用限制和安全限制等.用户程序执行的结果将被Online ...
- Mybatis入门(五)属性名和字段名不一致解决
在学Mybatis的时候都需要创建一个实体类,但创建实体类的变量必须和数据库的一样,这章就来解决这个有趣的问题 目录: 问题是这样: 输出的结果是: password为空,这就很难受: 解决方法: 第 ...
- 杭电OJ:1089----1096(c++)(ACM入门第一步:所有的输入输出格式)
1089:输入输出练习的A + B(I) 问题描述 您的任务是计算a + b. 太容易了?!当然!我专门为ACM初学者设计了这个问题. 您一定已经发现某些问题与此标题具有相同的名称,是的,所有这些问题 ...
随机推荐
- 【转】分享一份C语言写的简历
个人观点:文章想法很棒,作者的编码风格也很赞,可以从中学到不少东西.转载的文章是我都用心看过的,而且希望后续再可以回过头看的文章,努力让自己的能力越来越强,加油 这里黑客新闻吗?作者用代码更新了自己的 ...
- pageX,clientX,screenX,offsetX区别
pageX/pageY:鼠标相对于整个页面的X/Y坐标.注意,整个页面的意思就是你整个网页的全部,比如说网页很宽很长,宽2000px,高3000px,那pageX,pageY的最大值就是它们了.特别说 ...
- vs2015编译mysql c++ connector
目前MySQL Connector/C++的binary版本最高只支持VS2008,VS2015需要下载源码自行编译. 1.CMAKE 到官网下载最新的稳定版本 把bin目录添加到环境变量PATH中 ...
- C++ 句柄类
一.容器与继承 在容器中保存有继承关系的对象时,如果定义成保存基类对象,则派生类将被切割,如果定义成保存派生类对象,则保存基类对象又成问题(基类对象将被强制转换成派生类对象,而派生类中定义的成员未被初 ...
- Python3基础 使用clear() 清空一个字典
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- UVa 10132 - File Fragmentation
题目大意:有n个相同的文件,每个文件从中间分为两半,现在给你这2n个文件碎片,求原来完整的文件. 找出文件碎片长度的最大值和最小值,二者相加可得到原来文件的长度len.然后逐个进行拼接,将拼接后长度等 ...
- post请求时2种传参方式
@Testpublic void dopost(){ String httpurl = "https://jin.caimao.com/api/user/loginSalt"; M ...
- c++中冒号(:)和双冒号(::)的用法(void文章::变乱()、子类:父类)
1.冒号(:)的用法 (1)表示机构内位域的定义(即该变量占几个bit空间) typedef struct _XXX{ unsigned char a:4; unsigned char c; } ; ...
- Angular - - $compile编译服务与指令
$compile 这是个编译服务.编译一段HTML字符串或者DOM的模板, 产生一个将scope和模板连接到一起的函数. 编译服务主要是为指令编译DOM元素,下面的一大段也是主要介绍指令的. 下面是一 ...
- 随机矩阵(stochastic matrix)
最近一个月来一直在看Google排序的核心算法---PageRank排序算法[1][2],在多篇论文中涉及到图论.马尔可夫链的相关性质说明与应用[3][4][5],而最为关键,一直让我迷惑 ...