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;
}