HPU算法协会公开课第一期:【基础算法1】5.17

**

A - 前m大的数

还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大的M个数告诉她就可以了。
给定一个包含N(N<=3000)个正整数的序列,每个数不超过5000,对它们两两相加得到的N*(N-1)/2个和,求出其中前M大的数(M<=1000)并按从大到小的顺序排列。
// 把N个数放进数组cout,将其中元素两两相加的和放进一个数组so,最后将数组so中的数进行从大到小的排序,按照题目要求输出前M个数


```cpp
**#include<iostream>
#include<algorithm>
using namespace std;

int N,M,i,k,j=0,so[4500000],cont[3000];
bool cmp(int a,int b)  //将数组元素从大到小排列
{
	return a>b;
}
int main()
{
	while (scanf("%d %d",&N,&M) != EOF){
		for(i=0;i<N;i++)
		    scanf("%d",&cont[i]);
		for(i=0;i<N-1;i++){
			for(k=i+1;k<N;k++){
				so[j++]=cont[i]+cont[k];   //so[j]为数组cout中任意两数之和总共(N*N-1)/2个
			}				
	    }
	    sort(so,so+j,cmp);
	    for(i=0;i<M;i++){
	    	printf("%d",so[i]);
	    	if(i !=M-1 ) printf(" ");    //经过排序后,输出前M个数,也就是较大的M个数
		}
	    cout<<endl;
	}
	return 0;
}

B - 稳定排序

大家都知道,快速排序是不稳定的排序方法。
如果对于数组中出现的任意a[i],aj,其中a[i]==a[j],在进行排序以后a[i]一定出现在a[j]之前,则认为该排序是稳定的。

某高校招生办得到一份成绩列表,上面记录了考生名字和考生成绩。并且对其使用了某排序算法按成绩进行递减排序。现在请你判断一下该排序算法是否正确,如果正确的话,则判断该排序算法是否为稳定的。
// 用到结构体,要使稳定可以在结构体中加入int 类型的数代表顺序序号,通过sort函数进行排序,如果分数相等序号在前的先输出,最后满足题目要求输出
**

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;

struct student   //定义结构体
{
	char name[50];
	int score;
	int pl;  //pl代表输入的顺序的序号
}stu1[300],stu2[300];  //stu1代表初始学生信息,stu2代表经过某算法得出的结果

int N,i,k;
bool cmp(student a,student b){  //将学生信息按照分数以及序号进行排序
	if(a.score != b.score)
	    return a.score>b.score;
	else
	    return a.pl<b.pl;
}
int main()
{
    while(scanf("%d",&N) != EOF ){
	    for(i=0;i<N;i++){
		    scanf("%s %d",stu1[i].name,&stu1[i].score);
		    stu1[i].pl=i;
		}
	    for(i=0;i<N;i++)
		    scanf("%s %d",stu2[i].name,&stu2[i].score);
	    sort(stu1,stu1+N,cmp);  //对stu1中的学生进行排序
	    for(i=0;i<N;i++){  //对比tu2与排列好的stu1中的分数
		    if(stu2[i].score != stu1[i].score) {
			    printf("Error\n");  //如果不一致,输出Error
			    for(k=0;k<N;k++)
			        printf("%s %d\n",stu1[k].name,stu1[k].score);
			    break;
			}
		}
	    if(i==N)   //在此表示两者分数一致,比较tu2与排列好的stu1中的学生姓名
  	    for(i=0;i<N;i++){
		    if(strcmp(stu2[i].name,stu1[i].name) !=0 ){
		        printf("Not Stable\n");  //如果不一致,输出Not Stable
		        for(k=0;k<N;k++)
			        printf("%s %d\n",stu1[k].name,stu1[k].score);
			    break;
			}
	    }
	    if(i==N) printf("Right\n");  //在此表示两者学生信息完全一致,输出Right
    }
    return 0;
} 

C - 开门人和关门人

每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签
到、签离记录,请根据记录找出当天开门和关门的人。

// 通过分别比较M个人 进入机房的早晚 和 离开机房的早晚 可以得出开门和关门的人是谁,输出他们的名字即可。比较时间正好可以定义时间为字串,通过比较字符串的大小确定早晚

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;

struct student  //分别定义进入机房人的姓名,进入时间,离开时间
{
	char name[20];
	char begin[10];
	char end[10];
}stu[10000];

bool cmp1(student a,student b){  //对进入机房时间进行从小到大排序,序列的第一个即为开门的人
	return strcmp(a.begin,b.begin)<0;
}
bool cmp2(student a,student b){  //对离开机房时间进行从大到小排序,序列的第一个即为开门的人
	return strcmp(a.end,b.end)>0;
}

int main()
{   
	int N,k=0,M,Y,i;
	scanf("%d",&N);
	while(N--)  //N为天数
	{
		scanf("%d",&M);  //M为人数
		for(i=0;i<M;i++)
		{
			scanf("%s %s %s",stu[i].name,stu[i].begin,stu[i].end);
		}
		sort(stu,stu+M,cmp1);  //排序
		printf("%s ",stu[0].name);  //输出开门的人
		sort(stu,stu+M,cmp2);  //排序
		printf("%s\n",stu[0].name);  //输出关门的人
	}
	return 0;
}

E - {A} + {B}

给你两个集合,要求{A} + {B}.
注:同一个集合中不会有两个相同的元素.

// 把A B集合元素放在一起,进行从小到大排序,只输出连续相同元素中其中一个即可

#include<iostream>
#include<algorithm>
using namespace std;

int n,m,i,N[100000]; 

int main()
{
	while(scanf("%d %d",&n,&m) != EOF){  //n,m分别为两个集合元素数目
		for(i=0;i<n+m;i++){  //将它们放在N数组中输入值
			scanf("%d",&N[i]);
		}
		sort(N,N+n+m);  //sort函数默认从小到大paixv
		printf("%d",N[0]);
        for(i=1;i<n+m;i++)
        if(N[i] != N[i-1]) printf(" %d",N[i]);  //如果连续两个数相等,则跳过后面这个数
        printf("\n");		
	}
	return 0;
}

**

G - 不重复数字

给出N个数,要求把其中重复的去掉,只保留第一次出现的数。
例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。
// 将给出的数放进一个数组,用数组中第 i 个元素与该数组中第 i 个元素之前的 i-1个元素进行比较,如果这些元素中有元素与第 i 个元素相等,则跳过这个数不进行输出,直到数组元素结束。
**

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
	int T,N,i,k,num[50000];
    cin>>T;
	while(T--){  //T代表次数
		cin>>N;
		for(i=0;i<N;i++){
			cin>>num[i];
		}
		for(i=0;i<N;i++){  
			for(k=i-1;k>=0;k--)
		        if(num[i] == num[k]) break;  //如果第 i 个元素与 i 之前的任一元素相等则跳过这个数
		    if(k==-1)  //k=-1 代表第 i 个数之前没有数与之相等,则输出这个数
		        cout<<num[i]<<" ";
	    }
	    cout<<"\n";
	}
	return 0;
}

**

H - 表达式括号匹配

给出一个表达式,该表达式仅由字符(、)、+、-以及数字组成。

请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES";否则返回"NO"。
// 比较输入元素当中 ‘(’ 与 ‘)’ 个数是否相等,相等即匹配,不相等即不匹配


```cpp
#include<iostream>
#include<algorithm>
using namespace std;

int find(char x[2000],char c){  //定义函数,返回字符数组中所要求的字符个数
	int count=0;
	for(int i=0;x[i] != '\0';i++)
	    if(x[i]==c) count++;
	return count;
}
int main(){
	char x[2000];
	int j=0;
	while(scanf("%c",&x[j]) && x[j] != '\n') 
	    j++;
	if(find(x,'(') == find(x,')')) printf("YES");  //比骄 ‘(’ 与 ‘)’字符个数输出YES或NO
	else printf("NO");
	return 0;
}

**

I - 合并果子**

**
现在有n堆果子,第i堆有ai个果子。现在要把这些果子合并成一堆,每次合并的代价是两堆果子的总果子数。求合并所有果子的最小代价。
// 先将较小的两堆果子合并成一堆,再将现有的 i-1 堆果子中较小的两堆合并成一堆,知道只剩下一堆果子,求得最小代价

#include<iostream>
#include<algorithm>
using namespace std;

bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
    int P,T,n,i,count[1000],so[50]={0},q=0;
	scanf("%d",&T);  //输入 T 组数据
	P=T;
	while(P--)
	{
		scanf("%d",&n);  //输入 n 堆果子
		for(i=0;i<n;i++)
			scanf("%d",&count[i]);
		for(;n>=2;n--)
		{
		    sort(count,count+n,cmp);  //将 n 堆果子数量从大到小排序
		    count[n-2]=count[n-1]+count[n-2];  //将最后两堆果子放在一堆
			so[q]=so[q]+count[n-2];  //so代表代价
		}
		q++;
	}
	for(i=0;i<T;i++)
	    printf("%d\n",so[i]);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值