您的位置:首页 > 其它

贪心专题16题

2013-04-13 19:09 519 查看
贪心题目:



1001

部分背包问题。优先选取性价比高的,将单位价格进行排序,依次选取,直至满足条件。

[cpp] view
plaincopy

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int j,f;

double p;

}a[1000];

int n,m;

bool cmp(Node n1,Node n2){

return n1.p>n2.p;

}

int main(){

while(scanf("%d%d",&n,&m)!=EOF&&(n!=-1&&m!=-1)){

for(int i=0;i<m;i++){

scanf("%d%d",&a[i].j,&a[i].f);

a[i].p=a[i].j*1.0/a[i].f;

}

sort(a,a+m,cmp);

double ans=0;

int tmp=0;

for(int i=0;i<m;i++){

if(a[i].f+tmp>=n){

if(a[i].f+tmp==n)

ans+=a[i].j;

else

ans+=a[i].p*(n-tmp);

break;

}

else{

ans+=a[i].j;

tmp+=a[i].f;

}

}

printf("%.3f\n",ans);

}

return 0;

}

1002

没有交叉的区间是可以同时进行的。那么需要的次数便是某个点所经过的最大次数。

[cpp] view
plaincopy

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int t,n,x,y,a[205];

int main(){

scanf("%d",&t);

while(t--){

scanf("%d",&n);

memset(a,0,sizeof(a));

while(n--){

scanf("%d%d",&x,&y);

if(x>y)

swap(x,y);

for(int i=(x+1)/2;i<=(y+1)/2;i++)

a[i]++;

}

int ans=0;

for(int i=1;i<=200;i++)

ans=max(ans,a[i]);

printf("%d\n",ans*10);

}

return 0;

}

1003

贪心思想,先放6*6,格子已经全部放满,然后放5*5,剩下的空间可以用来放1*1,然后放4*4,剩余的空间可以放2*2,然后放1*1,之后放3*3,同理处理完剩余空间,最后考虑2*2,1*1。

[cpp] view
plaincopy

#include<iostream>

#include<cstring>

#include<cstdio>

using namespace std;

int a,b,c,d,e,f;

int main(){

int u[4]={0,5,3,1};

while(scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f)&&a+b+c+d+e+f){

int ans=d+e+f+(c+3)/4;

int x=d*5+u[c%4];

if(b>=x)

ans+=(b-x+8)/9;

int y=36*ans-36*f-25*e-16*d-9*c-4*b;

if(a>y)

ans+=(a-y+35)/36;

printf("%d\n",ans);

}

return 0;

}

1004

不错的题目,暴力可解,但是没有意思。可以发现规律

排序之后,对于每一组相邻的差a[pos]-a[pos-1],当i取0-(pos-1)以及j取pos-n时,i和j之间的差值必然包括a[pos]-a[pos-1]。

那么a[pos]-a[pos-1]出现的次数是i*(n-i)

[cpp] view
plaincopy

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int a[10000],n;

int main(){

while(scanf("%d",&n)!=EOF){

for(int i=0;i<n;i++)

scanf("%d",&a[i]);

sort(a,a+n);

LL ans=0;

for(int i=1;i<n;i++)

ans+=(LL)(a[i]-a[i-1])*i*(n-i);

printf("%I64d\n",ans*2);

}

return 0;

}

1005

按两个关键字从小到大排序,之后遍历。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int l,r;

}a[5000];

int n;

bool cmp(Node n1,Node n2){

return n1.l!=n2.l?n1.l<n2.l:n1.r<n2.r;

}

int main(){

int t;

scanf("%d",&t);

while(t--){

scanf("%d",&n);

for(int i=0;i<n;i++)

scanf("%d%d",&a[i].l,&a[i].r);

sort(a,a+n,cmp);

bool flag[5000];

memset(flag,false,sizeof(flag));

int ans=0;

for(int i=0;i<n;i++){

if(flag[i])

continue;

int L=a[i].l,R=a[i].r;

ans++;

for(int j=i;j<n;j++)

if(a[j].l>=L&&a[j].r>=R&&flag[j]==false){

L=a[j].l;

R=a[j].r;

flag[j]=true;

}

}

printf("%d\n",ans);

}

return 0;

}

1006

每个人手中有m张牌,有n个人,牌上的数字分别为1-n*m,互不相等。

赢的最少情况肯定是自己出大的,别人有大的,肯定压,否则别人出最小的。

每次选取最大的牌出,如果别人有大牌,则输,否则别人出最小的。不需要模拟,从大到小遍历一次。如果某张牌我有,说明我可以赢,+1,如果没有,说明别人可以比我大一次,-1。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int a[1005],n,m,k,cas=0;

bool flag[1005];

int main(){

while(scanf("%d%d",&n,&m)!=EOF&&n+m){

memset(flag,false,sizeof(flag));

for(int i=0;i<m;i++){

scanf("%d",&k);

flag[k]=true;

}

int ans=0,tmp=0;

for(int i=n*m;i>0;i--)

if(flag[i]){

tmp++;

ans=max(ans,tmp);

}

else

tmp--;

printf("Case %d: %d\n",++cas,ans);

}

return 0;

}

1007

离散化所有带宽。

枚举带宽,作为最小的带宽。然后在每一组选取满足最小带宽,而且价格最低的。

所以对于每一组按价格递增排序。优先考虑价格低的。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int b,p;

}a[400][400];

int t,m[400],B[160000],cnt,n;

bool cmp(Node n1,Node n2){

return n1.p<n2.p;

}

int main(){

scanf("%d",&t);

while(t--){

scanf("%d",&n);

cnt=0;

for(int i=0;i<n;i++){

scanf("%d",&m[i]);

for(int j=0;j<m[i];j++){

scanf("%d%d",&a[i][j].b,&a[i][j].p);

B[cnt++]=a[i][j].b;

}

sort(a[i],a[i]+m[i],cmp);

}

sort(B,B+cnt);

int CNT=1;

for(int i=1;i<cnt;i++)

if(B[i]!=B[CNT-1])

B[CNT++]=B[i];

double ans=0;

for(int k=0;k<CNT;k++){

int ptmp=0,flag=1;

for(int i=0;i<n;i++){

int j;

for(j=0;j<m[i];j++)

if(a[i][j].b>=B[k])

break;

if(j==m[i]){

flag=0;

break;

}

ptmp+=a[i][j].p;

}

if(flag)

ans=max(ans,B[k]*1.0/ptmp);

}

printf("%.3f\n",ans);

}

return 0;

}

1008

骑车去上学。时间为负的车子不用考虑,因为要不是追不上,要么追上也不是最快的。然后求出每辆车的所需时间,求出最小值。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node {

int v,t,need;

}a[10000];

int n;

int main(){

while(scanf("%d",&n)!=EOF&&n){

for(int i=0;i<n;i++)

scanf("%d%d",&a[i].v,&a[i].t);

for(int i=0;i<n;i++){

if(a[i].t<0)

a[i].need=inf;

else{

a[i].need=(int)((4500*3.6)/a[i].v+a[i].t);

if((int)(4500*3.6)%a[i].v)

a[i].need++;

}

}

int ans=a[0].need;

for(int i=1;i<n;i++)

ans=min(ans,a[i].need);

printf("%d\n",ans);

}

return 0;

}

1009

同样的根据价值递减排序,先满足价值高的先做,日期尽可能靠后。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int d,p;

}a[1000];

bool cmp(Node n1,Node n2){

return n1.p>n2.p;

}

int n,t;

int main(){

scanf("%d",&t);

while(t--){

scanf("%d",&n);

for(int i=0;i<n;i++)

scanf("%d",&a[i].d);

for(int i=0;i<n;i++)

scanf("%d",&a[i].p);

sort(a,a+n,cmp);

int ans=0;

bool flag[10000];

memset(flag,false,sizeof(flag));

for(int i=0;i<n;i++){

int j;

for(j=a[i].d;j>=1;j--)

if(flag[j]==false){

flag[j]=true;

break;

}

if(j==0)

ans+=a[i].p;

}

printf("%d\n",ans);

}

return 0;

}

1010

按结束时间排序,然后依次遍历。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int l,r;

}a[100];

int n;

bool cmp(Node n1,Node n2){

return n1.r!=n2.r?n1.r<n2.r:n1.l>n2.l;

}

int main(){

while(scanf("%d",&n)!=EOF&&n){

for(int i=0;i<n;i++)

scanf("%d%d",&a[i].l,&a[i].r);

sort(a,a+n,cmp);

int ans=1,k=0;

for(int i=1;i<n;i++)

if(a[i].l>=a[k].r){

ans++;

k=i;

}

printf("%d\n",ans);

}

return 0;

}

1011

贪心,每次优先选取价值高的,而且尽量时间靠后的。用flag数组标记,某天是否已经被利用,如果已经被利用,则往前遍历。

[cpp] view
plaincopy

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

int p,d;

}a[10000];

bool cmp(Node n1,Node n2){

return n1.p>n2.p;

}

int n;

int main(){

while(scanf("%d",&n)!=EOF){

for(int i=0;i<n;i++)

scanf("%d%d",&a[i].p,&a[i].d);

sort(a,a+n,cmp);

int ans=0;

bool flag[10005];

memset(flag,false,sizeof(flag));

for(int i=0;i<n;i++)

for(int t=a[i].d;t>0;t--)

if(flag[t]==false){

ans+=a[i].p;

flag[t]=true;

break;

}

printf("%d\n",ans);

}

return 0;

}

1012

对于每一个岛,存在一个区间,区间内任意位置建的雷达都能覆盖岛屿。这样就形成若干个区间。对于每一个区间从左到右遍历,尽可能选取最右端点,这样就能满足最多的区间。可以处理掉子区间。或者在遍历的时候遇到子区间,就尽可能取子区间的右端点。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

double l,r;

}a[1000];

int n,d;

bool cmp(Node n1,Node n2){

return n1.l<n2.l;

}

int main(){

int cas=0;

while(scanf("%d%d",&n,&d)!=EOF&&n+d){

bool flag=true;

for(int i=0;i<n;i++){

int x,y;

scanf("%d%d",&x,&y);

if(abs(y)>d)

flag=false;

if(!flag)

continue;

a[i].l=x-sqrt((double)d*d-y*y);

a[i].r=x+sqrt((double)d*d-y*y);

}

if(!flag){

printf("Case %d: -1\n",++cas);

continue;

}

sort(a,a+n,cmp);

int ans=1;

double pos=a[0].r;

for(int i=1;i<n;i++)

if(a[i].l>pos){

pos=a[i].r;

ans++;

}

else if(a[i].r<pos)

pos=a[i].r;

printf("Case %d: %d\n",++cas,ans);

}

return 0;

}

1013

对于每一个池塘,从左到右依次放木板。

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int n,d;

struct Node{

int l,r;

}a[10000];

bool cmp(Node n1,Node n2){

return n1.l<n2.l;

}

int main(){

while(scanf("%d%d",&n,&d)!=EOF){

for(int i=0;i<n;i++)

scanf("%d%d",&a[i].l,&a[i].r);

sort(a,a+n,cmp);

int ans=0,pos=-inf;

for(int i=0;i<n;i++){

if(a[i].l>pos){

ans+=(a[i].r-a[i].l+d-1)/d;

pos=(a[i].r-a[i].l+d-1)/d*d+a[i].l;

}

else if(a[i].r>pos){

ans+=(a[i].r-pos+d-1)/d;

pos=(a[i].r-pos+d-1)/d*d+pos;

}

}

printf("%d\n",ans);

}

return 0;

}

1014

黑书上的例题。首先枚举走过的湖泊数X,则从1走到X,路上花的时间可以算出。每一次选一个鱼最多的湖泊钓鱼,对于每个湖泊来说,由于 在任何时候鱼的数目只和在这个湖泊里钓鱼的次数有关,和总次数无关。所以这样是最优的。

[cpp] view
plaincopy

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

int main()

{

int n,h,f[30],d[30],t[30],Case=0;

while(scanf("%d",&n),n>0)

{

if(Case!=0) printf("\n");

Case++;

scanf("%d",&h);

h=h*60;

for(int i=1;i<=n;i++)

scanf("%d",&f[i]);

for(int i=1;i<=n;i++)

scanf("%d",&d[i]);

t[1]=0;

for(int i=1;i<=n-1;i++)

{

int a;

scanf("%d",&a);

t[i+1]=t[i]+a*5;

}

int fish=0;

int f_temp[30];

int spe[30];

int spe_temp[30];

int tt;

for(int i=1;i<=n;i++)

spe[i]=-1;

for(int i=1;i<=n;i++)

{

int sum=0;

tt=h-t[i];

for(int j=1;j<=n;j++)

f_temp[j]=f[j];

memset(spe_temp,0,sizeof(spe_temp));

while(tt>=5)

{

int mmax=0,maxj=-1;

for(int j=1;j<=i;j++)

{

if(f_temp[j]>mmax)

{

mmax=f_temp[j];

maxj=j;

}

}

if(maxj==-1)

break;

tt=tt-5;

spe_temp[maxj]++;

sum+=f_temp[maxj];

f_temp[maxj]=f_temp[maxj]-d[maxj];

}

if(sum>fish)

{

fish=sum;

for(int j=1;j<=n;j++)

spe[j]=spe_temp[j];

spe[1]+=tt/5;

}

else if(sum==fish)

{

bool flag=false;

for(int j=1;j<=n;j++)

if(spe[j]<spe_temp[j])

{

flag=true;

break;

}

else if(spe[j]>spe_temp[j])

break;

if(flag)

{

fish=sum;

for(int j=1;j<=n;j++)

spe[j]=spe_temp[j];

spe[1]+=tt/5;

}

}

}

for(int i=1;i<n;i++)

printf("%d, ",spe[i]*5);

printf("%d\nNumber of fish expected: %d\n",spe
*5,fish);

}

return 0;

}

1015

经典贪心,详见http://blog.csdn.net/acm_cxlove/article/details/7720218

1016

肯定所有的物品都要买,依次选取价值高的物品,这样打折的物品价格也高

[cpp] view
plaincopy

#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int t,n,a[20000];

int main(){

scanf("%d",&t);

while(t--){

scanf("%d",&n);

for(int i=0;i<n;i++)

scanf("%d",&a[i]);

sort(a,a+n);

int ans=0;

for(int i=n-3;i>=0;i-=3)

ans+=a[i];

printf("%d\n",ans);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: