当前位置:首页 » 《休闲阅读》 » 正文

sort的使用和贪心算法_m0_53387935的博客

23 人参与  2022年01月01日 18:14  分类 : 《休闲阅读》  评论

点击全文阅读


sort函数


先简单介绍一下sort函数

sort对给定区间所有元素进行排序,头文件是#include <algorithm> 


Sort函数有三个参数:

  1. 第一个是要排序的数组的起始地址。
  2. 第二个是结束的地址(最后一位要排序的地址的下一地址)
  3. 第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

下面详细介绍一下sort的各种用法


1.整数数组直接从小到大排列

#include<algorithm>
#include<cstdio>

using namespace std;
//输入: 
//    先输入数组长度 n
//    然后再输入n个整数
//输出
//    从小到大顺序输出数组 
int main()
{
	int i,n,a[200];
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	for(i=0;i<n;i++)
	{
		printf("%d\n",a[i]);
	}
	return 0;
}

2.整数数组从小到大排序(用cmp)

#include<algorithm>
#include<cstdio>
 
using namespace std;
 
//输入: 
//    先输入数组长度 n
//    然后再输入n个整数
//输出
//    从小到大顺序输出数组 
 
int cmp(int x,int y){
	return x<y;
}
 
int main()
{
	int i,n,a[200];
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	sort(a,a+n,cmp);
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
	puts("");
	return 0;
}

3.整数数组从大到小排序,这个只需要把2中的cmp的不等号换一下就好了

#include<algorithm>
#include<cstdio>
 
using namespace std;
 
//输入: 
//    先输入数组长度 n
//    然后再输入n个整数
//输出
//    从大到小顺序输出数组 
 
int cmp(int x,int y){
	return x>y;
}
 
int main()
{
	int i,n,a[200];
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	sort(a,a+n,cmp);
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
	puts("");
	return 0;
}

4.结构体数组简单排序(单属性)

#include<algorithm>
#include<cstdio>

using namespace std;
//输入: 
//    先输入结构体数组长度 n
//    然后再输入n个整数,表示结构体的其中的一个属性q 
//输出
//    根据结构体数组的属性q的从大到小顺序,输出结构体数组
struct s{
	int q;
	int b;
}a[200];
int cmp(s x,s y)
{
	return s.q>y.q
}
int main()
{
	int i,n;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i].q);
	}
	sort(a,a+n,cmp);
	for(i=0;i<n;i++)
	{
		printf("%d 原位置:%d\n",a[i].q,a[i].b);
	}
	puts(" ");
	return 0;
}

5.结构体数组双属性排序
 

#include<algorithm>
#include<cstdio>

using namespace std;
//输入: 
//    先输入结构体数组长度 n
//    然后接下去n行,每行输入两个整数,表示结构体的其中的两个属性p和q 
//输出
//    根据p属性的大小进行从大到小排序,在p相等的情况下,则根据q的大小进行从大到小排序 
 
/*
样例输入:
5
3 5
4 7
6 3
4 9
3 2 
*/ 
struct s
{
	int p;
	int q;
}a[200];

int cmp(s x,s y){
	if(x.p==y.p)
		return x.q>y.q
	return x.p>y.p
}
int main(){
	int i,n;
	scanf("%d",&n);
	for(i=0;i<n,i++)
	{
		scanf("%d%d",&a[i].p,&a[i].q);
	}
	sort(a,a+n,cmp);
	puts("排序后");
	for(i=0;i<n;i++)
	{
		printf("%d %d\n",a[i].p,a[i].q);
	}
	puts(" ");
	return 0;
}

6.结构体数组双属性排序2    //   所有的结构体排序都可以把以上的cmp函数,写成结构体运算符重载operator<

#include<algorithm>
#include<cstdio>
 
using namespace std;
 
//输入: 
//    先输入结构体数组长度 n
//    然后接下去n行,每行输入两个整数,表示结构体的其中的两个属性p和q 
//输出
//    根据p属性的大小进行从大到小排序,在p相等的情况下,则根据q的大小进行从大到小排序 
 
/*
样例输入:
5
3 5
4 7
6 3
4 9
3 2 
*/ 
 
struct S{
	int q;
	int p;
	bool friend operator <(S a,S b){
		if(a.p==b.p) return a.q>b.q;
		return a.p>b.p;
	}
}a[200];
 
int main(){
	int i,n;
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d%d",&a[i].p,&a[i].q);
	sort(a,a+n);
	puts("排序后:"); 
	for(i=0;i<n;i++)
		printf("%d %d\n",a[i].p,a[i].q);
	puts("");
	return 0;
}

7.字符串数组排序(char字符串)

#include<cstdio>
#include<sstring>
#include<algorithm>
using namespace std;
//输入: 
//    先输入字符串数组长度 n
//    然后再输入n个字符串 
//输出
//    从小到大顺序输出字符串数组
char as[200][50];
int cmp(int x,int y)
{
	return strcmp(as[x],as[y])==-1;
}
int main()
{
	int i,n,a;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%s",as[i]);
		a[i]=i;
	}
	sort(a,a+n);
	for(i=0;i<n;i++)
	{
		printf("%s\n",as[a[i]]);
	}
	return 0;
}

8.字符串数组排序(string 字符串)

#include<bits/stdc++.h>

using namespace std;

int main()
{
	printf("请输入要排序的字符串:\n");
	string s; cin>>s;
	sort(s.begin(),s.end());
	printf("排序完后的字符串为:\n");
	cout<<s<<endl;
	return 0;
}

最优装载问题


1.给出N个物体,第一个物体重量为W1
2.选择尽量多的物体,使得总重量不超过C

思路
拿最小的??
尽量多装质量小的??这正确吗?
假如有这么一种方案是没有优先装质量小的,那么我们始终可以
把它换成质量更小的,而数目没有变化
因此,我们可以确定:我们只需要把所有物体按重量从小到大排序,依次选择
每个物体,直到放不下为止,就能得到最优解了
虽然证明不是特别严谨,要真正证明的话用反证法
下面上代码:

#include<iostream>
#include<algorithm>
#define MAXN 1000005
using namespace std;
int w[MAXN];//每件古董的重量 
int main()
{
	int c,n;//c:载重量,n古董数 
	int sum = 0;//装入古董的数量 
	int tmp = 0;//装入古董的重量 
	cin >> c >> n;	 
	for(int i= 1; i <= n; ++i)
		cin >> w[i];
	sort(w+1,w+1+n);
	for(int i = 1; i <= n; ++i)
	{
		tmp += w[i];//这个要在if外面 
		if(tmp<=c)
	 		sum++;
		else
			break;
	}
	cout << sum << endl;
	return 0;
}

问题二:合并果子
有N堆果子,每堆果子有自己的果子数AI,每次合并可以将任意两堆果子合并,合并小号的体力
为两堆果子果子数之和
求消耗的最小体力
1<N<10000
思路:

显然,选最小的两堆果子合并N-1次即可
每次加完后可能就不是从小到大了,所以每次加完都要再次排序

#include<bits/stdc++.h>

using namespace std;
long long  sum,a[100001],n,d;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	d=n;
	sort(a+1,a+n+1);
	for(int i=1;i<=d-1;i++)
	{
		a[1]+=a[2];
		for(int j=2;j<=n-1;j++)
		a[j]=a[j+1];
		sum+=a[1];
		n--;
		sort(a+1,a+n+1);
	//	for(int i=1;i<=n;i++)
	//	cout<<a[i]<<" ";
	//	cout<<"               "<<sum<<endl;
	}
	cout<<sum<<endl;
	return 0;
}

问题三:国王游戏
恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左右手分别写下一个整数,
国王自己也在左右手上各写一个整数。然后,让这n位大臣排成一排,国王站在队伍的最前面。排好队后,
所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的
左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。国王不希望某一个大臣获得特别多
的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣所获得的奖金尽可能少。注意,
国王的位置始终在队伍的最前面。(金币数大于1)
【输入格式】
第一行为一个整数n(1<=n<=1000)表示大臣的人数
第二行为两个整数a,b(0<a,b<10000),分别表示国王左手和右手上的整数
接下来的n行,每行为两个整数a,b分别表示每个大臣左手和右手上的整数
【输出格式】
仅一行为一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数
样例及解释
输入:
3
1 1
2 3
7 4
4 6
输出:
2

分析

我们可以枚举每一种情况
1 2 3 => 2(获得奖赏最多的大臣获得的金币数)
1 3 2 => 2
2 1 3 => 2
2 3 1 => 9
3 1 2 => 2
3 2 1 => 9
但是枚举显然不是一个好的做法,因为n挺大,要枚举到死啊,所以显然有好的做法,我们来分析一下
显然在交换前面的数时,后面的数答案是没有变化的,当然对交换的前面的数也没有影响
也就是说相邻两个人位置的交换只会对这两个人产生影响。我们便从这里为切入点,分析调换相邻二元组的顺序对
答案产生的影响
设这两个人的位置为i和i+1,左手数字为a[i]和a[i+],右手数字为b[i]和b[i+1],两个人的金币
数为w[i]和w[i+1]。
记p[i]=a[1]*a[2]*...*a[i]
则未调换位置时,k1=w[i]=p[i-1]/b[i]; k2=p[i-1]*a[i]/b[i+1];
有ans1=max{k1,k2};
调换位置后, k3=p[i-1]/b[i+1]; k4=p[i-1]*a[i+1]/b[i];
有ans2=max{k3,k4};
显然k1<k4,k3<k2;
如果ans1<ans2,则必有k2<k4  <=> a[i]*b[i]<a[i+1]*b[i+1]
所以为了让ans取得最小值,我们需要把a[i]*b[i]较小的放在前面,那么我们
以a[i]*b[i]为关键字排序即可
同时统计答案时一定不要忘了写高精度

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
int len = 1;//表示高精度数据的长度
int sum[100001] = {0,1};//高精度数据计算结果 
struct minister{
	ll left;
	ll right;
} m[1000001];
bool cmp(minister a,minister b){
	return a.left * a.right < b.left * b.right;
}
void multiplicative(ll x){//高精度乘法 
	for(int i = 1;i <= len; i++){
		sum[i] *= x; //各位数乘x,如1111×20 = (1000+100+10+1)×20 
	} 
	for(int i = 1;i <= len; i++){
		sum[i + 1] += sum[i] / 10;//获得进位,因为相乘结果可能为 10 3 13 4,需转化为 1 0 4 3 4
		sum[i] %= 10;
	}
	len++;//因为是sum[i+1],所以肯定会计算到sum[len+1],所以需要len++
	while(sum[len] / 10){//观察最高位是否有进位,因为可能有经过前面的操作后可能有 100 3的情况  
		sum[len + 1] = sum[len] / 10;
		sum[len] %= 10;
		len++; 
	} 
    //经过前面的一波操作后,最后可能会导致sum[len]的位置上有0,若为0则需要消除
	if(sum[len] == 0)
	len--; 
}
void division(){//高精度除法,这里只需要进行一次操作,所以不需要参数 
	//思路依旧很简单,如2345/5=(2000+300+40+5)/5,小学生除法 
	//->2 3 4 5 ->0 23(3 + 2%5*10) 4 5 -> 0 4 34(4 + 23%5*10) 5 -> 0 4 6 45(5 + 34%5*10)
	for(int i = len; i >= 1; i--){
		sum[i - 1] += (sum[i] % m[n].right * 10);
		sum[i] /= m[n].right;
	}
	//这波操作必然导致一堆前导0,需消除 
	while(!sum[len]){
		len--;
	}
	//防止除完了
	if(len == 0) cout << "1" << endl; 
} 
int main(){
	cin >> n;
    cin >> m[0].left >> m[0].right;
	for(int i = 1;i <= n; i++)
	cin >> m[i].left >> m[i].right;
	sort(m + 1, m + 1 + n, cmp);
	for(int i = 0;i < n; i++){
		multiplicative(m[i].left); 
	}
	division();
	for(int i = len; i >= 1; i--)
	cout << sum[i];
}


点击全文阅读


本文链接:http://zhangshiyu.com/post/32504.html

数组  排序  整数  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1