前言
贪心比较简单,但是要掌握好结构体排序的构造
正文
1.哈夫曼编码
题目描述
给定一只含有小写字母的字符串;输出其哈夫曼编码的长度。
输入
第一行一个整数T,代表样例的个数,接下来T行,每行一个字符串,0<T<=2000,字符串长度0<L<=1500.
3
hrvsh
lcxeasexdphiopd
mntflolfbtbpplahqolqykrqdnwdoq
输出
10
51
115
思路
要构造哈夫曼编码首先就必须要计算出每个字母出现的频率,扫描一遍即可;接下来就需要用这些频率来构造哈夫曼树,在这里需要使用优先队列这个数据结构,将频率全部push进入优先队列按从小到大排列后,使用贪心算法,每次都是将最小的两个频率拿出来构造哈夫曼树,两数的和再次push进队列,重复进行即可。
code
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
char s[2000];
cin>>s;
int fre[26]={0};
int len=strlen(s);
for(int i=0;i<len;i++)
{
fre[s[i]-'a']++;
}
priority_queue<int,vector<int>,greater<int> >q;
for(int i=0;i<26;i++)
{
if(fre[i]>0)
{
q.push(fre[i]);
}
}
int sum=0;
while(q.size()>=2)
{
int a=q.top();
q.pop();
int b=q.top();
q.pop();
sum+=(a+b);
q.push(a+b);
}
cout<<sum<<endl;
}
return 0;
}
2.最优装载
题目描述
轮船载重有限将尽可能多的集装箱装上轮船
Description
有一批集装箱要装上一艘载重量为C的轮船。其中集装箱i的重量为wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
Input
输入的第一个为测试样例的个数T( T <= 100 ),接下来有T个测试样例。每个测试样例的第一行是一个整数n( n <= 1000 )和一个非负数C( C <= 10000 ),分别表示集装箱的个数以及轮船的载重量。接下来有n行,每行一个非负数,表示每个集装箱的重量。
Output
输出最多装集装箱的个数和最终的承重量。
Sample Input
1
5 100
20
50
120
99
30
思路
贪心选择策略:重量最轻者优先装载
将装船过程划为多步选择,每步装一个货箱,每次从剩下的货箱中选择重量最轻的货箱。如此下去直到所有货箱均装上船或船上不能再容纳其他任何一个货箱。
code
#include<iostream>
#include<algorithm>
using namespace std;
int w[100];
int c;
int n;
int load(int k,int z)
{
int count=0;
sort(w,w+k);
for(int i=0;i<k;i++)
{
if(z>=w[i])
{
count+=w[i];
z-=w[i];
}
else
{
break;
}
}
return count;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>c;
for(int i=0;i<n;i++)
{
cin>>w[i];
}
int ans=load(n,c);
cout<<ans<<endl;
}
return 0;
}
3.配对元素
题目描述
给出2个序列A={a[1],a[2],…,a[n]},B={b[1],b[2],…,b[n]},从A、B中各选出n个元素进行一一配对(可以不按照原来在序列中的顺序) ,并使得所有配对元素差的绝对值之和最大。
输入
输入的第1行为1个整数n 第2行包含n个整数,题目中的A序列。 第3行包含n个整数,题目中的B序列。
4
2 5 6 3
1 4 6 7
输出
一个数,最大配对
3与6配对,2与7配对,5与4配对,6与1配对,绝对值之差和为14 对于10%的数据,有n≤20; 对于30%的数据,有n≤100; 对于50%的数据,有n≤1000; 对于100%的数据,有n≤10000;a[i],b[i]≤1000
14
思路
要使相减的绝对值之和最大,也就是要尽量使得两个数的差要大一点,贪心策略自然就是用a序列最大值减去b序列最小值。
code
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
int a[100];
int b[100];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++)
{
cin>>b[i];
}
sort(a,a+n);
sort(b,b+n);
int j=0,sum=0;
for(int i=n-1;i>=0;i--)
{
sum+=fabs(a[i]-b[j]);
j++;
}
cout<<sum<<endl;
return 0;
}
4.活动安排
题目描述
给出n个活动的开始和结束时间,要求找出所有活动集合中不冲突的最大活动数
思路
结构体,按结束时间从小到大排序这就是贪心策略:越早结束约优先考虑,第一个默认加入,其后进行判断到底是否可以加入集合,如可以就计数
code
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct node
{
int begin;
int end;
}node;
bool cmp(node a,node b)
{
return a.end<b.end;
}
int main()
{
int n;
while(cin>>n)
{
node work[100000];
for(int i=0;i<n;i++)
{
cin>>work[i].begin>>work[i].end;
}
sort(work,work+n,cmp);
int count=1;
int temp=work[0].end;
for(int i=1;i<n;i++)
{
if(work[i].begin>=temp)
{
count++;
temp=work[i].end;
}
else
{
continue;
}
}
cout<<count<<endl;
}
return 0;
}
5.区间包含
题目描述
已知 n 个左闭右开区间 [a,b),对其进行 m 次询问,求区间[l,r]最多可以包含 n 个区间中的多少个区间,并且被包含的所有区间都不相交。
输入
输入包含多组测试数据,对于每组测试数据:
第一行包含两个整数 n ,m (1≤n≤100000,1≤m≤100)
接下来 n 行每行包含两个整数 a ,b (0≤a<b≤10^9)
接下来 m 行每行包含两个整数 l ,r (0≤l<r≤10^9)
输出
对于每组测试数据,输出 m 行,每行包含一个整数
样例输入
4 3
1 3
2 4
1 4
1 2
1 2
1 3
1 4
样例输出
1
1
2
思路
和活动安排问题大致相同
code
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct node
{
int left;
int right;
}node;
bool cmp(node a,node b)
{
return a.right<b.right;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
node nnum[100005],mnum[105];
for(int i=0;i<n;i++)
{
cin>>nnum[i].left>>nnum[i].right;
}
for(int i=0;i<m;i++)
{
cin>>mnum[i].left>>mnum[i].right;
}
sort(nnum,nnum+n,cmp);
for(int i=0;i<m;i++)
{
int count=0;
int t=mnum[i].left;
for(int j=0;j<n;j++)
{
if(nnum[j].left>=t)
{
if(nnum[j].right<=mnum[i].right)
{
count++;
t=nnum[j].right;
}
else
{
break;
}
}
}
cout<<count<<endl;
}
}
return 0;
}
6.homework
题目描述
临近开学了,大家都忙着收拾行李准 备返校,但 I_Love_C 却不为此担心! 因为他的心思全在暑假作业上:目前为止还未开动。
暑假作业是很多张试卷,我们这些从试卷里爬出来的人都知道,卷子上的题目有选择题、填空题、简答题、证明题等。而做选择题的好处就在于工作量很少,但又因为选择题题目都普遍很长。如果有 5 张试卷,其中 4 张是选择题,最后一张是填空题,很明显做最后一张所花的时间要比前 4 张长很多。但如果你只做了选择题,虽然工作量很少,但表面上看起来也已经做了4/5的作业了。
I_Love_C决定就用这样的方法来蒙混过关,他统计出了做完每一张试卷所需的时间以及它做完后能得到的价值(按上面的原理,选择题越多价值当然就越高咯)。
现在就请你帮他安排一下,用他仅剩的一点时间来做最有价值的作业。
输入
测试数据包括多组。每组测试数据以两个整数 M,N(1<M<20,1<N<10000) 开头,分别表示试卷的数目和 I_Love_C 剩下的时间。接下来有 M 行,每行包括两个整数 T,V(1<T<N,1<V<10000)分别表示做完这张试卷所需的时间以及做完后能得到的价值,输入以 0 0 结束。
输出
对应每组测试数据输出 I_Love_C 能获得的最大价值。保留小数点 2 位
提示:float 的精度可能不够,你应该使用 double 类型。
样例输入
4 20
4 10
5 22
10 3
1 2
0 0
样例输出
37.00
思路
该题为贪心法解决背包问题,物体可以被拆分,先按照平均价值排序即可
code
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef struct node
{
double time;
double value;
double avg;
}node;
bool cmp(node a,node b)
{
return a.avg>b.avg;
}
int main()
{
int m,n;
while(cin>>m>>n&&(m!=0&&n!=0))
{
node paper[100];
for(int i=0;i<m;i++)
{
cin>>paper[i].time>>paper[i].value;
paper[i].avg=paper[i].value/paper[i].time;
}
sort(paper,paper+m,cmp);
double temp=(double)n;
double sum=0;
for(int i=0;i<m;i++)
{
if(temp>=paper[i].time)
{
sum+=paper[i].value;
temp-=paper[i].time;
}
else
{
sum+=paper[i].avg*temp;
break;
}
}
cout<<fixed<<setprecision(2)<<sum<<endl;
}
return 0;
}