贪心算法
例题一:FatMouse' Trade
一只老鼠有M磅猫食,然后在N个房间里面用猫食换JavaBean。
房间i中能用F[i]磅的猫食来换J[i]磅的JavaBean,而且老鼠可以在一个房间里根据一定比例a%来换取JavaBean. 现在他是这任务分配给你:告诉他,他的JavaBeans的获取能最多。
输入:The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1's. All integers are not greater than 1000.
输出:For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.
结构体和cmp函数:
struct sa {
int j; // javabeen 的数量
int f; // 猫食的数量
double awk; // f[i]/j[i]的比值
}data[2002];
int cmp( const sa &a,const sa &b)
{
return (a.awk) > (b.awk);
}
上面是关于结构体数组定义之类的,下面是主函数,只是一部分不完全
while(scanf(“%d%d”,&m,&n)!=EOF)
{
sum=0.0;k=0;
if (m==-1&&n==-1) break;
for(int i=0;i<n;i++)
{
cin>>data[i].j>>data[i].f;
data[i].awk=(double)data[i].j/(double)data[i].f ;
}
sort(data,data+n,cmp);
for(k=0;k<n;k++)
{
if (m>=data[k].f)//大于 F[i]
{
sum=sum+data[k].j; //都换了
m=m-data[k].f; }
else
{ sum=sum+(double)m*data[k].awk;
break; }
}
printf("%.3f\n",sum);
}
补充一下:sort函数默认是从小到大
例题二:时间序列问题
今年暑假不AC(hdu2037)
目标是能看尽量多的完整节目
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
struct sa {
int x;
int y;
}data[10000];//又开大了,开101就行
int cmp(const sa &a,const sa &b)
{
return a.y < b.y;
}
sa tmp;
while(cin>>n&&n!=0)
{
sum=0;
for(int i=0;i<n;i++)
cin>>data[i].x>>data[i].y;
sort(data,data+n,cmp);
sum=1;
tmp=data[0];
for(int j=1;j<n;j++)
{
if (tmp.y<=data[j].x)
{
sum++;
tmp=data[j];
}
}
cout<<sum<<endl;
3.区间覆盖问题
Hdu1050
int main(int argc, char *argv[])
{
int start[401],end[401],data[401];
int t,n,tmp,aaa;
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<=400;i++) data[i]=0;
for(int i=0;i<n;i++)
{
cin>>start[i]>>end[i];
if ( start[i]>end[i])
{tmp=start[i];start[i]=end[i];end[i]=tmp;}
if(start[i]%2==1) start[i]=(start[i]+1)/2;
else start[i]=start[i]/2;
if (end[i]%2==1) end[i]=(end[i]+1)/2;
else end[i]=end[i]/2;
for(int k=start[i];k<=end[i];k++)
data[k]++;
}
aaa=data[1];
for(int j=2;j<=200;j++)
if (aaa<data[j]) aaa=data[j];
cout<<aaa*10<<endl;
}
然而有的区间覆盖的题用上面的那个过不了,会超内存啊,下面介绍的这道题就是如此。
51nod1428
有若干个活动,第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,要把活动都安排完,至少需要几个教室?Input
第一行一个正整数n (n <= 10000)代表活动的个数。
第二行到第(n + 1)行包含n个开始时间和结束时间。
开始时间严格小于结束时间,并且时间都是非负整数,小于1000000000
Output
一行包含一个整数表示最少教室的个数。
Input示例
3
1 2
3 4
2 9
Output示例
2
这道题的精髓就在于数给的很大,数组开不了那么大,那么我们应该如何做呢,看着道题,起点和终点加一起只有20000个点,我们直接离散化,就是把这些点单独拿出来进行操作就行了
精髓是如果只需要教室的个数,我们可以把所有开始时间和结束时间排序,遇到开始时间就把厚度加1,遇到结束时间就把厚度减1,显然最初始和最后结束时的厚度是0,在一系列厚度变化的过程中,峰值(最大值)就是最多同时进行的活动数,也是我们至少需要的教室数。
下面是代码
#include <iostream>
#include <algorithm>
using namespace std;
struct sa
{
long long xu;
int v;
}a[20005];
int cmp(const sa&a,const sa&b)
{
return a.xu<b.xu;
}
int main()
{
int s=0,ans=0;
int n;
while(cin>>n)
{
for(int i=0;i<2*n;i++)
{
cin>>a[i].xu;
if(i%2==0)
a[i].v=1;
else a[i].v=-1;
}
sort(a,a+2*n,cmp);
for(int j=0;j<2*n;j++)
{
ans+=a[j].v;
if(ans>s)
s=ans;
}
cout<<s<<endl;
}
return 0;
}