贪心1——2021-01-28更

这两天写贪心问题集合的博客。

贪心1——SSL 贪心板块

T1 删数问题

题目:

现有一个高精度的正整数 n(<=240位) ,去掉其中任意 s 个数字后,剩下的数字按原左右顺序组成一个新数。
请根据给出的 n 和 s ,请寻找一种方案,使得剩下的数字组成的新数最小。

输入
第1行:一个正整数n。
第2行:s(s < n的位数)。
输出

最后剩下的最小数。

输入样例
175438
4

输出样例
13

思路:

第一次做的时候,我的想法很简单,就是删掉前s大的数字,再输出,但是,显然我的思路错了,我再认真思考了一下,找了一个反例分析,195482 删去2个数,这个数字如果按照一开始的想法做的话,最终的结果是1542,但实际上它的结果应该是1482,那么应该怎么写呢,我发现,这道题目应该是尽量从高位删除,使得左边len-s个数的值最小,就是说我们把从第一位到第len位中前s个比它右边一个数大的数删掉就好了,最后输出时注意删掉前导0就好了。

代码:

#include<bits/stdc++.h> 
using namespace std;
int n,k,a[250],cd,g=0;
string s;
int main()
{
	cin>>s>>k;
	cd=s.size();
	for(int i=1;i<=k;i++)
	{
		for(int j=0;j<cd-1;j++)
		{
			if(s[j]>s[j+1])
			{
				for(int x=j;x<cd-1;x++)
					s[x]=s[x+1];
				break;	
			}
		}
	}			
	while(s[g]=='0'&&cd>1)
	{
		g++;
		cd--;
	}
	if(g>s.size()-k)
	{
		cout<<0;
		exit(1);
	}
	for(int i=g;i<s.size()-k;i++)
		cout<<s[i];
	return 0;
} 

T2 均分纸牌

题目:

有N堆纸牌,编号分别为1,2,…,n。每堆上有若干张,但纸牌总数必为n的倍数.可以在任一堆上取若干张纸牌,然后移动。
移牌的规则为:在编号为1上取的纸牌,只能移到编号为2的堆上;在编号为n的堆上取的纸牌,只能移到编号为n-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
例如:n=4,4堆纸牌分别为:① 9 ② 8 ③ 17 ④ 6
移动三次可以达到目的:
从③取4张牌放到④ (9 8 13 10)
再从③区3张放到② (9 11 10 10)
然后从②去1张放到①(10 10 10 10)。

输入
第1行为一个整数N,表示纸牌堆数(1<=N<=100)
第2行为N个整数,表示每堆纸牌的初始数量Ai(1<=Ai<=10000)。

输出
所有堆均达到相等时的最少移动次数。

输入样例
4
9 8 17 6

输出样例
3

思路:

我看到这道题目第一时间就想到用两次循环,一次从左到右,一次从右到左,逐个判断,但发现不对,方法出现了偏差,经过提点和谨慎思考,其实可以发现,通过一次循环,将缺的或多的直接就转移走,因为如果刚才循环过的牌堆不够,我只需要直接从当前这堆往刚才循环过的那堆传就好了,如果当前堆数目不够平均数,下一堆会传回来的,因为我们可以知道,牌的数量绝对是足够的,哪怕我当前是-10张(假设一下),但我可以从下一堆牌直接补回来,至于下一堆牌的缺失,后面还会有牌来补的,我们要做的就是让当前这堆牌达到平均数就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,h,a[110],pj;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		pj+=a[i];
	}	
	pj/=n;
	if(a[n]>pj)
	{
		a[n-1]+=a[n]-pj;
		a[n]=pj;
		h++;
	}
	for(int i=n-1;i>=1;i--)
	{
		if(a[i+1]<pj)
		{
			a[i]-=pj-a[i+1];
			a[i+1]=pj;
			h++;
		}
		if(a[i]>pj)
		{
			a[i-1]+=a[i]-pj;
			a[i]=pj;
			h++;
		}
	}
	cout<<h;
	return 0;
}

T3 排队打水(二)

排队打水(一)比较简单,不写了。

题目:

有n个人到m个水龙头去打水,他们装满水桶的时间分别为t1,t2,…,tn(ti为整数且各不相等),应如何安排他们的打水顺序才能使得他们花费的总时间最少?

输入
第1行:两个整数n和m,分别表示人和水龙头的个数。
第2行:n个数,分别表示每个人装水的时间。

输出
一个整数,表示总花费的最少时间。

输入样例
6 2
5 4 6 2 1 7

输出样例
40

思路:

这道题目就是(一)的PLUS版,在时间最少的情况下又增加成了m个水龙头。
核心点:先sort一次,将人的打水顺序以打水时长来排,这样子就会出现一个规律,设我有2个水龙头,第x个人必然到第x%2个水龙头打水,因为我已经将他们打水的顺序排好了,所以第一个人一定比第二个人打水快,那么第三个人要想省时间,就一定会去第一个水龙头,同理,因为第一个人+第三个人的时间一定大于第二个人,所以第四个人就会去第二个水龙头,以此类推,我只需要用找到循环,再把那些人分别规划到它该待的水龙头,再把时间求出来,就很好办了。

代码:

#include<bits/stdc++.h> 
using namespace std;
int n,m,h,a[1010],c[1010],b[400],k,l;

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	sort(a+1,a+1+n);
	k=n/m;
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=m;j++)
		{
			b[j]+=a[++l];
			c[l]=b[j];
		}	
	}
	k=n%m;	
	if(k!=0)
	{
		for(int i=1;i<=k;i++)
		{
			b[i]+=a[++l];	
			c[l]=b[i];
		}
	}
	for(int i=1;i<=n;i++)
		h+=c[i];
	cout<<h;	
	return 0;
} 

今天就发这些吧,总的来说,贪心就是在做题思路中将眼前的利益最大化,然后接下来的每一步中实现这种利益最大化。其实贪心就是一种经验,没有规律可循,也没有模板,需要靠多练习来熟练运用。

贪心系列——贪心2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值