贪心例题
1:数列极限
https://ac.nowcoder.com/acm/problem/50166
思路:
考虑3个数a,b,c. a < b < c,有三种取法:
m1 = (ab+1)c = abc + c
m2 = (ac+1)b = abc + b
m3 = (bc+1)a = abc + a
m1 > m2 > m3
可以看出来要最后值最大的话优先取两个小的数,值最小的话优先取两个最大的数。
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#define LL long long
#define inf 0x3f3f3f3f
const int mod = 1e9+7;
using namespace std;
int main()
{
int n;
priority_queue<int,vector<int>,less<int> >q1;
priority_queue<int,vector<int>,greater<int> >q2;
cin >> n;
for(int i = 0; i < n; i++){
int x;
cin >> x;
//sl.push_back(x);
q1.push(x);
q2.push(x);
}
cin >> n;
int mmin,mmax;
while(q1.size() != 1){
int a = q1.top();
q1.pop();
int b = q1.top();
q1.pop();
q1.push(a*b+1);
}
mmax = q1.top();
while(q2.size() != 1){
int a = q2.top();
q2.pop();
int b = q2.top();
q2.pop();
q2.push(a*b+1);
}
mmin = q2.top();
int m = mmin - mmax;
cout << m;
return 0;
} 2:均分纸牌
思路:
1:这类问题一般是让所有的数到平均数次数最少。
2:我们要移动的次数最少,那么对于每堆牌,我们考虑最多移动一次,因为移动两次或两次以上是一种浪费。采用“移动一次使得一堆牌数达到平均值”的贪心策略:先把每堆的牌数减去平均数,然后由左而右的顺序移动纸牌。若第i堆纸牌的张数a[i]不为0,则将值移动到下一堆。
3:求出最后的a[i]后,我们可以发现a[i]<0表示需要到右边堆去拿a[i]张牌,那么第i+1堆离平均数为a[i+1] += a[i],a[i]>0那么我们就拿a[i]张牌给第i+1堆,那么第i+1堆离平均数为a[i+1] += a[i]。
https://ac.nowcoder.com/acm/problem/16739
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#define LL long long
#define inf 0x3f3f3f3f
const int mod = 1e9+7;
using namespace std;
int main()
{
int a[105],n,sum;
cin >> n;
sum = 0;
for(int i = 1; i <= n; i++) cin >> a[i],sum += a[i];
int ave = sum / n;
for(int i = 1; i <= n; i++) a[i] -= ave;
int ans = 0;
for(int i = 1; i <= n; i++){
if(a[i] != 0) a[i+1] += a[i],ans++;
// if(a[i] != 0){
// //a[i+1] += a[i];
// if(a[i] < 0) cout << i+1 << "-->" << i << ":" << abs(a[i]) << endl;
// else cout << i << "-->" << i+1 << ":" << a[i] << endl;
// }
}
cout << ans;
return 0; 3:接水问题
思路:从每一组接水的人中选出接水时间最少的那个人,让下一个人接替他的位置接水并加上他的接水时间,这样依次算出每个水龙头的接水总时间,最后选最长节水时间即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
//void print(char a[])
//{
// printf("%d %c\n",strlen(a),a[2]);
//}
int main()
{
int n,m,a[100005],b[105];
cin >> n >> m;
int ans = 0,mmax = 0;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
int k = 1;
for(int j = 1; j <= m; j++){
if(b[k] > b[j]){
k = j;
}
}
b[k] += a[i];
}
for(int i = 1; i <= m; i++) {
mmax = max(mmax,b[i]);
}
cout << mmax;
return 0;
} 4:删数问题
贪心策略:优先从最高位查找,如果从前往后是递增的,则删除递增序列的最后一个,如果递减就删除递减序列的第一个。
一段string的操作代码:
int main()
{
string s;
cin >> s;
s.erase(s.begin()+0);
s.insert(s.begin()+0,'2');
cout << s;
return 0;
} #include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int main()
{
string s;
int m,n;
while(cin >> s){
scanf("%d",&m);
for(int i = 1; i <= m; i++){
int n = s.length();
for(int i = 0; i < n; i++){
if(i == n - 1){
s.erase(s.begin()+i);
break;
}
if(s[i] > s[i + 1]){
s.erase(s.begin()+i);
break;
}
}
}
int flag = 0;
n = s.length();
for(int i = 0; i < n; i++){
if(s[i] == '0' && flag == 0) continue;
else{
cout << s[i];
flag = 1;
}
}
if(flag == 0) cout << '0';
cout << "\n";
}
return 0;
} 4:货仓选址
给定数轴上的n个点,在数轴上的所有点中,中位数离所有顶点的距离之和最小。凡是能转化为这个模型的题目都可以用中位数求解。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
int a[100005];
int main()
{
int n,x,m,t;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a+1,a+n+1);
int ans = 0;
int d;
if(n & 1) d = (a[n/2+1] ) / 2;
else d = (a[n/2] + a[n/2+1]) / 2;
for(int i = 1; i <= n; i++){
ans += abs(a[i] - d);
}
cout << ans;
return 0;
}
顺丰集团工作强度 369人发布