【全网首发】洛谷贪心题解集合

贪心

1.P2240 【深基12.例1】部分背包问题

【深基12.例1】部分背包问题 - 洛谷

思路

万不要被题目给误导了,这道题是贪心。

所有金币都可以分开,也就是说只要按照性价比最高的取一定得到的价值最大。

性价比就是这堆金币的价值除以重量。

只需要把这n堆金币按性价比排序就行了。

然后依次遍历,如果背包中剩余可以拿的重量大于等于这堆金币的重量,就全拿,否则直接装满。

直接装满这里注意一下整型转浮点的细节就好了。

AC

#include
using namespace std;
double ans,t;
struct gold{
	double m,r;
}a[105];
bool cmp(gold u,gold v){
	return u.r>v.r;
}
int n;
int main(){
	cin>>n>>t;
	for(int i=1;i<=n;i++){
		double x,y;
		cin>>x>>y;
		a[i].m=x;
		a[i].r=y/x;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(a[i].m

2.P1803 凌乱的yyy / 线段覆盖

凌乱的yyy / 线段覆盖 - 洛谷

思路

这道题考查的应该是贪心, 贪心的地方在于每次都选择结束时间最早的那场比赛,最后的参赛次数应该是最高的(详情请见其他dalao的题解),所以代码就十分简单了,利用sort快排把结束顺序从小到大排列,然后根据上场比赛的结束时间和本场比赛的开始时间一一检查能否参加就可以了。

AC

#include
#define f first //将first用f表示
#define s second//将second用s表示
using namespace std;
typedef pairpi;
int const m=1e6+5;
pi a[m];
int n;
int main(){
	cin>>n;
	for(int i=0;i>a[i].s>>a[i].f;
	}
	sort(a,a+n);
	int last=0,ans=0;
	for(int i=0;i=last){
			ans++;
			last=a[i].f;
		}
	}
	cout<

3.P1190 [NOIP2010 普及组] 接水问题

[NOIP2010 普及组] 接水问题 - 洛谷

思路

首先,我们理解了题目,哪个人装完水之后,就轮到队伍的下一个人来接水.So,下一个来接水的人,一定是去当前装水的m个人中最快的那个人的位置继续装水.

Then,我们就可以从第m+1个人开始帮他找位置(PS:为什么不是从第一个人开始?因为前m个人已经在装水了,他们的位置随便定(写程序的时候不用管)).因为要去速度最快的那个人的位置,所以,到那个位置装水的人的时间之和也是最短的!

那么,我们就可以利用数组中前m个位置来储存相对应位置接水的人时间之和.这样的话,每次就可以先找m个接水位置中,当前时间之和最短的来装水(即把a[i]加到a[1](当前总用时最短的位置)),就OK啦!

最后,再看一下前m个位置中那个用的时间是最短的,cout就可以完成啦!

AC

#include
using namespace std;
int s[11000],ans; 
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s[i];
	}
	int t=m+1;
	while(t<=n+m){
		for(int i=1;i<=m;i++){
			s[i]--;
			if(s[i]==0){
				s[i]=s[t];
				t++;
			}
		}
		ans++;
	}
	cout<

4.P1080 [NOIP2012 提高组] 国王游戏

[NOIP2012 提高组] 国王游戏 - 洛谷

思路

看到这道题的使得获得奖赏最多的大臣,所获奖赏尽可能的少,我的第一想法是二分答案。但是又仔细想了想,答案不具有单调性,二分是行不通的。

再看看这道题,我感觉可以用贪心来做。也就是说先用贪心确定一种最优的方案,再在这个排列队伍中求得答案。

可以这样思考,相邻两个的人交换对于前面的人答案没影响(这不是废话么),而且对于后面的人答案也没有影响(这里很关键)。也就是说相邻两人的位置交换只会对这两个人产生影响。那么我们就先考虑这两个人。

设这两个人分别为i和i+1。左手数字为a[i]和a[i+1],右手数字为b[i]和b[i+1]。两人的金币数为w[i]和w[i+1]。

记P[i]=a[1]*a[2]a[3]...*a[i]

可得:

w[i]=P[i-1]/b[i];

w[i+1]=P[i]/b[i+1];

又P[i]=P[i-1]*a[i]

那么 w[i+1]=P[i-1]*a[i]/b[i+1]=w[i]*a[i]*b[i]/b[i+1]

不难看出,在这个相邻的二元组中,前面的数不受后面的影响,而后面的金币数决定于w[i],a[i],b[i]。

推广到整个排队方案,前面的金币数和a[i],b[i]都会影响后面的答案。贪心原则便出来了:按a[i]*b[i]为关键字从小到大排序,相同的顺序无所谓。最后再扫一遍,算出答案即可。

此题需要注意一点:乘除法都要写高精度,且答案有10000多位。

AC

#include
#define ll long long
#define ld long double
using namespace std;
string hmul(string a,string  b){
    int c[500005];
    memset(c,0,sizeof c);
    int x[a.size()],y[b.size()];
    memset(x,0,sizeof x);
    memset(y,0,sizeof y);
    for(unsigned int i=0;i=10){
            c[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }
    string ci;
    bool p=1;
    for(int i=a.size()+b.size()-1;i>=0;i--){
        if(c[i]==0&&p) continue;
        else{
            p=0;
            ci+=c[i]+'0';
        }
    }return ci;
}
string hdiv(string a,int b){
    int x[50005];
    int y[50005];
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    for(unsigned int i=0;ib.size()?a:b;
    return a>b?a:b;
}
string tur_str(int num){
    string str;
    while(num){
        str+=num%10+'0';
        num/=10;
    }
    reverse(str.begin(),str.end());
    return str;
}
int n;
struct aa{
    int l,r;
}a[100005];
bool cmp(aa a,aa b){
    return (a.l*a.r)<(b.l*b.r);
}
int main(){
    cin>>n;
    cin>>a[0].l>>a[0].r;
    for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r;
    sort(a+1,a+n+1,cmp);
    string ans="0";
    string xx=tur_str(a[0].l);
    for(int i=1;i<=n;i++){
        ans=smx(ans,hdiv(xx,a[i].r));
        xx=hmul(xx,tur_str(a[i].l));
    }cout<

​​​​​

你可能感兴趣的:(算法)