贪心
参考资料
贪心
贪心算法(Greedy Algorithm),是用计算机来模拟一个「贪心」的人做出决策的过程。这个人十分贪婪,每一步行动总是按某种指标选取最优的操作。而且他目光短浅,总是只看眼前,并不考虑以后可能造成的影响。
可想而知,并不是所有的时候贪心法都能获得最优解,所以一般使用贪心法的时候,都要确保自己能证明其正确性。
反悔贪心
思路是无论当前的选项是否最优都接受,然后进行比较,如果选择之后不是最优了,则反悔,舍弃掉这个选项;否则,正式接受。如此往复。
例题
洛谷 P1209 [USACO1.3] 修理牛棚 Barn Repair
牛棚一个紧挨着另一个被排成一行,牛就住在里面过夜。有些牛棚里有牛,有些没有。所有的牛棚有相同的宽度。
自门遗失以后,Farmer John 必须尽快在牛棚之前竖立起新的木板。他的新木材供应商将会供应他任何他想要的长度,但是吝啬的供应商只能提供有限数目的木板。 Farmer John 想将他购买的木板总长度减到最少。
给出 ,表示木板最大的数目、牛棚的总数、牛的总数;以及每头牛所在牛棚的编号,请算出拦住所有有牛的牛棚所需木板的最小总长度。
代码(1)
#include <bits/stdc++.h>
using namespace std;
const int N=205;
int a[N],b[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m,s,c;
cin>>m>>s>>c;
for(int i=1;i<=c;i++)
{
cin>>a[i];
}
if(m>c)
{
cout<<c<<'\n';
return 0;
}
sort(a+1,a+c+1);
int ans=a[c]-a[1]+1;
for(int i=2;i<=c;i++)
{
b[i-1]=a[i]-a[i-1];
}
sort(b+1,b+c+1,greater<int>());
for(int i=1;i<=m-1;i++)
{
ans-=b[i]-1;
}
cout<<ans<<'\n';
return 0;
}
洛谷 P1792 [国家集训队] 种树
A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。
园林部门得到指令后,初步规划出 个种树的位置,顺时针编号 到 。并且每个位置都有一个美观度 ,如果在这里种树就可以得到这 的美观度。但由于 城市土壤肥力欠佳,两棵树决不能种在相邻的位置( 号位置和 号位置叫相邻位置。值得注意的是 号和 号也算相邻位置)。
最终市政府给园林部门提供了 棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将 棵树苗全部种上,给出无解信息。
代码(1)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=200005;
struct Node
{
int v,l,r;
}a[N];
bool vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i].v;
}
if(m>n/2)
{
cout<<"Error!"<<'\n';
return 0;
}
priority_queue<pair<int,int>> q;
for(int i=1;i<=n;i++)
{
q.push({a[i].v,i});
a[i].l=(i-2+n)%n+1;
a[i].r=i%n+1;
}
ll ans=0;
while(m)
{
int u=q.top().second;
q.pop();
if(vis[u])continue;
ans+=a[u].v;
m--;
int x=a[u].l,y=a[u].r;
vis[x]=vis[y]=1;
a[u].l=a[x].l;a[a[x].l].r=u;
a[u].r=a[y].r;a[a[y].r].l=u;
a[u].v=a[x].v+a[y].v-a[u].v;
q.push({a[u].v,u});
}
cout<<ans<<'\n';
return 0;
}