ProblemA(HDU2037)
这道解题,是希望看到节目尽可能多,那么安排好前面的节目后,如果剩下的时间更多,能选择的节目就更多。
所以贪心策略是对每个节目的结束时间排序,目的是使剩余时间留下,再判断还能看几个节目。对节目时间的排序结束后,依次判断,这次要看的节目的开始时间是否大于上次看的节目的结束时间,若是大于,则这个节目时可以完整观看的,若是小于则是不能完整观看的,所以跳到下一个节目继续判断 。
#include<stdio.h>
#include<algorithm>
using namespace std;
int n;
struct show
{
int s;
int e;
}pro[110];
bool cmp(show a,show b)
{
return a.e<b.e;
}
int main()
{
while(scanf("%d",&n)!=EOF&&n)
{
int cnt=1,i;
for(i=0;i<n;i++)
{
scanf("%d%d",&pro[i].s,&pro[i].e);
}
sort(pro,pro+n,cmp);
int tmp=pro[0].e;
for(i=1;i<n;i++)
{
if(pro[i].s>=tmp)
{
cnt++;
tmp=pro[i].e;
}
}
printf("%d\n",cnt);
}
return 0;
}
ProblemB(HDU4310)
要求掉的血最少,应该要从攻击力/血量(掉血速度)最大的先杀,因为你每次打敌人一滴血就要相应减去还存在的敌人的攻击和的血量,所以肯定要从攻击力/血量大的开始,才能得到掉的最低血量。
也就是对攻击力/血量排序,再直接按顺序打,将损失的血量算出来就好。
#include <iostream>
#include <algorithm>
using namespace std;
struct per
{
double hp,dps;
double bi;
}p[30];
int cmp(const per &a,const per &b)
{
if (a.hp!=b.hp)
return a.bi>b.bi;
else return a.dps>b.dps;
}
int main()
{
int n;
while (cin>>n)
{
int i,j,shp=0,sdps=0,chp=0,cdps=0,sum=0;
for (i=0;i<n;i++)
{
cin>>p[i].dps>>p[i].hp;
p[i].bi=p[i].dps/p[i].hp;
shp+=p[i].hp;
sdps+=p[i].dps;
}
sort(p,p+n,cmp);
for (i=0;i<n;i++)
{
sum+=(sdps-cdps)*p[i].hp;
cdps+=p[i].dps;
}
cout<<sum<<endl;
}
return 0;
}
ProblemC(HDU1789)
扣分大的当然要想办法做掉。所以对分数按从大到小排次序,然后枚举限定的时间,若是某一天没有被标记,就用这一天来完成这一门作业,若是枚举到0了,说明在限定时间内没有哪一天可以完成这门作业,那么就扣除这门课的分数。当然完成的日期要倒着枚举,也就是说尽量把前面的日子空出来,以应对后面更多的作业。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
struct ss
{
int time,p;
}t[100000];
int f[100000];
int cmp(const ss a,const ss b)
{
if(a.p>b.p)
return 1;
else if(a.p==b.p&&a.time<b.time)
return 1;
else
return 0;
}
int main()
{
int text,n;
scanf("%d",&text);
while(text--)
{
scanf("%d",&n);
memset(f,0,sizeof(f));
int i;
for(i=1;i<=n;i++)
scanf("%d",&t[i].time);
for(i=1;i<=n;i++)
scanf("%d",&t[i].p);
sort(t+1,t+1+n,cmp);
int sum=0;
for(i=1;i<=n;i++)
{
int j;
for(j=t[i].time;j>=1;j--)
if(!f[j])
{
f[j]=1;
break;
}
if(j==0)
sum+=t[i].p;
}
printf("%d\n",sum);
}
return 0;
}
ProblemD(HDU4864)
将任务以x从大到小排序(x相同时以y从大到小排序)。然后也用相同排序方法排序机器。开始遍历任务,找出所有xi(xi>=xj),从中选择yi最小的一个作为这个任务的运行机器。为什么这么贪心,因为若还存在任务(xk,yk)使得这个机器能被使用,但xj>=xk,所以获得金钱更多,优先选择j;若k不能使用这个机器,那么必定也就不存在其他机器能被使用,除非是新加入的机器,但新加入的必定不能完成任务j,所以完成任务保证了最多。
这里曾有人问我为什么先按x排再按y排一定可以保证最优,凭什么不是y先排?请看数据,价值为500*x+2*y,而y的范围最大只有100。y最大幅度的增加带来的价值还不如X加1。当然是按x排咯。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL __int64
const int maxn=1e5+10;
struct node{
int x,y;
}e[maxn],f[maxn];
int c[101];
int cmp(node a,node b)
{
if(a.x==b.x)return a.y>b.y;
return a.x>b.x;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j,k,num=0;
LL ans=0;
for(i=0;i<n;i++)
scanf("%d%d",&e[i].x,&e[i].y);
for(i=0;i<m;i++)
scanf("%d%d",&f[i].x,&f[i].y);
sort(e,e+n,cmp);
sort(f,f+m,cmp);
memset(c,0,sizeof(c));
for(i=0,j=0;i<m;i++)
{
while(j<n&&e[j].x>=f[i].x)
{
c[e[j].y]++;
j++;
}
for(k=f[i].y;k<=100;k++)
{
if(c[k])
{
num++;
c[k]--;
ans=ans+500*f[i].x+2*f[i].y;
break;
}
}
}
printf("%d %I64d\n",num,ans);
}
return 0;
}
ProblemE(POJ1017)
由于盒子和箱子的高均为h,因此只需考虑底面积的空间。
6*6的盒子,每个盒子独占一个箱子。
5*5的盒子,每个盒子放入一个箱子,该箱子的剩余空间允许放入的最大尺寸为1*1,且最多放11个。
4*4的盒子,每个盒子放入一个箱子,该箱子的剩余空间允许放入的最大尺寸为2*2。
3*3的盒子,每4个刚好独占一个箱子,不足4个3*3的,剩下空间由2*2和1*2填充。
2*2的盒子和1*1的盒子主要用于填充其他箱子的剩余空间,填充后的多余部分才开辟新箱子装填。
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int p[4]={0,5,3,1},a[10];
//3×3的放完后,余下的放入新箱子后,还可以放几个2×2的包裹(下标对应余数)
while(1)
{
int sum=0;
for(int i=1;i<=6;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
if(sum==0)
break;
sum=0;
sum=a[4]+a[5]+a[6]+a[3]/4;
if(a[3]%4!=0) sum++;
int need2=a[4]*5+p[a[3]%4];
if(need2<a[2])
{
sum+=(a[2]-need2)/9;
if((a[2]-need2)%9!=0) sum++;
}
int need1=sum*36-a[2]*4-a[3]*9-a[4]*16-a[5]*25-a[6]*36;
//需要的1×1的个数,即所有箱子的总面积减去后5种盒子的总面积
if(need1<a[1])
{
sum+=(a[1]-need1)/36;
if((a[1]-need1)%36!=0)
sum++;
}
printf("%d\n",sum);
}
return 0;
}