目录
贪心我觉的最难的在于证明,如何这样最优。
P1223 排队接水 【贪心 / 前缀和】
https://www.luogu.com.cn/problem/P1223
思路: 将其从小到大排序,这样的话平均时间最小,求其前缀和数组。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct student
{
int id;
int t;
}stu[1005];
bool cmp(student a,student b)
{
return a.t<b.t;
}
long long int sum;
long long int s[1005];
int main(void)
{
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>stu[i].t,stu[i].id=i;
sort(stu+1,stu+n+1,cmp);//从小到大排序
for(int i=1;i<=n;i++) s[i]=s[i-1]+stu[i].t;//前缀和数组
for(int i=1;i<=n;i++) cout<<stu[i].id<<" ",sum+=s[i-1];
printf("\n%.2lf\n",sum*1.0/n);
return 0;
}
P1803 凌乱的yyy / 线段覆盖 【贪心 / 区间合并】
https://www.luogu.com.cn/problem/P1803
#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
vector<PII> ve;
int main(void)
{
int n; cin>>n;
int a,b;
for(int i=0;i<n;i++) cin>>a>>b,ve.push_back({a,b});
sort(ve.begin(),ve.end());
int ans=1,endx=ve[0].y;
for(int i=1;i<ve.size();i++)
{
if(endx<=ve[i].x) ans++,endx=ve[i].y;//情况二
if(ve[i].y<endx) endx=ve[i].y;//情况一
}
if(n==0) cout<<0<<endl;
else cout<<ans<<endl;
}
P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G 【贪心 / 堆 / 优先队列】
https://www.luogu.com.cn/problem/P1090
方法: 优先队列,它的底层就是堆,故可以直接用,而不用手写堆了。
先排列,取最小的数,再将和入队。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
priority_queue<int, vector<int>, greater<int> >a;//队首的数小
int sum;
int temp;
int main(void)
{
int n; cin>>n;
int number;
for(int i=0;i<n;i++) cin>>number,a.push(number);
while(a.size()>1)//合并成一个堆了
{
temp+=a.top(),a.pop();
temp+=a.top(),a.pop();
a.push(temp);
sum+=temp;
temp=0;
}
cout<<sum<<endl;
return 0;
}
看题解区大佬的做法:
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a[n+5];
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
int ans=0;
for(int i=1;i<=n-1;i++)
{
ans+=(a[i]+a[i+1]);
a[i+1]+=a[i];//俩数合并
for(int j=i+1;j<=n-1;j++)//将合并后的后面数据排序
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
else
break;
}
}
printf("%d\n",ans);
return 0;
}
P1208 [USACO1.3]混合牛奶 Mixing Milk 【典型的贪心】
https://www.luogu.com.cn/problem/P1208
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
vector<PII> ve;
int ans;
int main(void)
{
int sum,n; cin>>sum>>n;
int a,b;
for(int i=0;i<n;i++) cin>>a>>b,ve.push_back({a,b});
sort(ve.begin(),ve.end());
for(int i=0;i<n;i++)
{
if(sum==0) break;//买完了
if(sum<ve[i].y) ans+=sum*ve[i].x,sum=0;//这一家可以买完了
if(sum>=ve[i].y) ans+=ve[i].x*ve[i].y,sum-=ve[i].y;//买的还不足够
}
cout<<ans<<endl;
return 0;
}
P1094 [NOIP2007 普及组] 纪念品分组 【贪心 / 双指针】
https://www.luogu.com.cn/problem/P1094
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[50005];
int ans;
int main(void)
{
int sum; cin>>sum;
int n; cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
int l=0,r=n-1;
while(l<r)
{
if(a[l]+a[r]<=sum) ans++,l++,r--;
else r--,ans++;
}
if(l==r)cout<<ans+1<<endl; //最后一次只有一个人
else cout<<ans<<endl; //最后一组看好组完一队
return 0;
}
P4995 跳跳!
https://www.luogu.com.cn/problem/P4995
要想最大: 一定是 一个最大的数,一个最小的数一次排列。 数据范围很小直接暴力模拟。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int a[305];
long long int sum=0;
bool cmp(int a,int b)
{
return a>b;
}
int main(void)
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
sum+=pow(a[n-1],2);//先找打最大的数跳
int temp=a[n-1];
n--;
while(1)
{
sort(a,a+n,cmp); //从大到小排
int w=a[n-1];//取最小的数
sum+=pow(abs(temp-w),2);
n--;//去掉跳过的数
if(n==0) break;//都跳完了
sort(a,a+n);
temp=a[n-1];//取最大的数
sum+=pow(abs(temp-w),2);
n--;
if(n==0) break;
}
cout<<sum<<endl;
return 0;
}