贪心小结 [贪心专题16题]

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

自己开的专题,用于集训队暑期集训。题目来源已经给出。

1001

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

#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

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

#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。

#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)

#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

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

#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。

#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

离散化所有带宽。

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

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

#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

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

#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

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

#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

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

#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数组标记,某天是否已经被利用,如果已经被利用,则往前遍历。

#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

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

#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

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

#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,路上花的时间可以算出。每一次选一个鱼最多的湖泊钓鱼,对于每个湖泊来说,由于 在任何时候鱼的数目只和在这个湖泊里钓鱼的次数有关,和总次数无关。所以这样是最优的。

#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[n]*5,fish); 
    } 
    return 0; 
}


1015

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

 

1016

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

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


 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值