很久没写博客了很惭愧
贪心在《算法导论》上竟然排在动态规划后面
贪心的基本思想:先把问题分成若干步骤,再在完成一个问题的每一步中,都选择局部最优解,最后导致全局最优解。
听起来很简单,但是贪心需要严格的证明。
洛谷p1094纪念品分组
由于一组最多两个物品,所以考虑尽量更多利用空间。
对于已排好序的a[1],a[2].....a[n-1],a[n],对于a[1],将它与可以安排的最大的物品安排在一起,一定是最优的。
否则可能导致这个最大的物品没有别的物品搭配而多出一组。
#include<bits/stdc++.h>
using namespace std;
int a[30005];
bool my(int a,int b)
{
return(a>=b);
}
int main()
{
int w,n;
scanf("%d%d",&w,&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1,my);
int i=1,j=n;
int sum=0;
while(i<=j)
{
if(a[i]+a[j]<=w)//如果能放一起,则一起放
{
sum++;
i++;
j--;
}
else//如果不能放一起,则大的单独放
{
sum++;
i++;
}
}
printf("%d",sum);
return 0;
}
洛谷p1791线段覆盖
算导上有严格的证明,但是它从dp引到贪心我根本看不懂。
直接贴做法吧......首先将线段端点调整为左端点<=右端点;然后根据右端点从小到大排序;第三,扫描一遍,遇到与当前最后的线段相交则删去,否则选择它并且设为当前最后的线段。
#include<bits/stdc++.h>
using namespace std;
struct line
{
int begin,end;
};
line a[1000];
bool mycmp(line a1,line b1)
{
return(a1.end<=b1.end);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].begin,&a[i].end);
if(a[i].begin>a[i].end)
{
int k=a[i].begin;
a[i].begin=a[i].end;
a[i].end=k;
}
}
sort(a+1,a+n+1,mycmp);//根据右端点排序
line t;
int s=n;
t.end=a[1].end;
for(int i=2;i<=n;i++)
{
if(a[i].begin<t.end)s--;//删除该线段
else t.end=a[i].end;//选择该线段
}
printf("%d",s);
return 0;
}