关于贪心算法的一点小见解~

关于贪心算法,也称贪婪算法,顾名思义是在当前状态下尽可能多的获得东西,不考虑之后的情况,也就是只求局部最优解,而局部最优解是否能成为全局最优解就不一定了,因此贪心法能解决的问题有限,在某些情况下,贪心法的确能取得最优解,但很多时候,其所求得的只是次优解,因此,判断一个问题用贪心法得到的局部最优解是否能成为全局最优解十分重要,在分析一个问题是,贪心法可以选择的判断标准有很多:如在背包问题中,是选取总价值最大的还是单位重量价值最大的来装入背包呢?不同的选取标准采用贪心法所得到的不一定是最优解,因此,选取一个合适,正确的判断标准就很重要了。

贪心算法经典问题一:可分解背包问题

         有一个背包,可以装若干个物品,该背包有最大容量W(能装入的物品的最大总重量),每个物品有各自的重量和价值,并且每个物品可以分解开来装,请问怎么装入物品能使装入背包的东西价值最大?

         分析:由于物品可以分解,则只要每次都取能装入的单位重量价值最大的物品即可,这就是贪心策略:总取单位重量价值最大的物品。不难发现,在此问题中,物品可以分解成为了判断标准的选取的重要条件:因为背包能装入的重量有限,所以使背包的每一单位重量的价值最大成为了解此题的策略,下面上代码:

//假设有n个物品可以选,每个物品都可以分割,重量和价值分别为w[i]和v[i],ave[i]为每一个物品的单位重量的价值
#include <stdio.h>

int main(void)
{
int n,W,w[30],v[30],ave[30],i,j,k,t,sum;
while (scanf ("%d%d",&n,&W) != EOF)
{
max = sum = 0;
for (i = 0;i < n;i++)
{
scanf ("%d%d",&w[i],&v[i]);
ave[i] = v[i] / w[i];//求出每个物品的单位质量价值
printf ("%d ",ave[i]);
}
for (i = 0;i < n -1;i++)//选择排序
{
k = i;
for (j = i + 1;j < n;j++)
{
if(ave[j] > ave[k])
{
k = j;
}
}
if(k != i)//将单位重量价值大的放前面
{
t = w[i];
w[i] = w[k];
w[k] = t;
t = v[i];
v[i] = v[k];
v[k] = t;
t = ave[i];
ave[i] = ave[k];
ave[k] = t;
}
}
for (i = 0;i < n;i++)
{
if(w[i] <= W)//如果背包剩余的重量可以装的下整个物品,就装
{
sum += v[i];
W -= w[i];//装入后背包剩余的重量为本来的减去装了的
}
else//当背包已经不能完整的装入当前单位重量价值最大的物品时,就可进行分解,即背包剩余的重量全部以该物品的单位重量价值装入
{
sum += (W * ave[i]);
break;//因为背包已经没有可以装入的空间,退出选择,不难发现,此时的sum已经为最优解
}
}
printf ("%d\n",sum);
}

return 0;
}

贪心算法经典问题二:电视节目问题

“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%...”

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
分析:乍一看,要尽可能看多的完整节目,有三种策略可以选择:1.尽可能看开始时间早的电视节目,等等,如果一个电视节目的开始时间很早(假设是0点),但结束时间很晚(假设是24点),那你还要看这个节目吗?(你一定很绝望),很明显,这种策略行不通。2.尽可能看播放时间短的节目,但是播放时间段的节目不一定在前面的时间段,这样子那你就不看前面的节目了吗?同时,在考虑播放时间段的节目要不要看时,我们还得考虑其他节目的结束时间,开始时间等等因素,很明显,这也不是一个很好的策略。3.尽可能看结束时间早的节目,也就是说,有一天有24个小时,我们只要保证尽可能在早的时间看完一个节目,就能使得看的完整节目最多。YES!这就是最优策略。接下来上代码

#include <stdio.h>

int main(void)
{
int i,j,k,t,n,start[100],end[100],sum,m;
while (scanf ("%d",&n) != EOF)//输入这一天的电视节目总数n
{
if(n == 0)
{
break;
}
sum = 1;
for (i = 0;i < n;i++)
{
scanf ("%d%d",&start[i],&end[i]);//输入这n个节目的开始时间和结束时间
}
for (i = 0;i < n - 1;i++)
{
k = i;
for (j = i + 1;j < n;j++)
{
if(end[j] < end[k])
{
k = j;
}
}
if(k != i)//选择排序,将结束时间早的节目放到前面,结束时间晚的节目放到后面
{
t = start[k];
start[k] = start[i];
start[i] = t;
t = end[i];
end[i] = end[k];
end[k] = t;
}
}
m = end[0];//排完序后第一个节目,也就是结束时间最早的节目一定要看,这时下一个要看的结束时间早节目的开始时间一定不能比这个节目的时间早
for (i = 1;i < n;i++)
{
if(start[i] >= m)//只有当前节目的开始时间不比上一个已经看的节目的结束时间早时,才看这个节目
{
sum += 1;
m = end[i];//下一个节目的比较标准成了这个节目的结束时间
}
}
printf ("%d\n",sum);//最后输出这一天能看的完整节目最多的数量
}

 

return 0;
}

posted @ 2017-04-18 11:15  505算法小菜`  阅读(273)  评论(0编辑  收藏  举报