本文已参与「新人创作礼」活动,一起开启掘金创作之路。
【C语言】贪心法的设计与实现
一、目的
掌握贪心法的设计思想、具体实现和时间复杂度分析。
二、实验内容
先用伪代码或流程图描述利用动态规划解决的算法解决方案,再用程序实现,计算时间复杂度,记录最终测试数据和测试结果
2.1实验内容:
2.1.1 背包问题
2.1.2 活动安排问题
2.1.3 找零钱问题
2.1.4图着色问题
三、设计和编码
3.1算法设计
3.1.1背包问题
输入:物品个数n和背包容量c
输出:最大价值
1.for(int i = 1; i <= n; ++i)
2.输入n与c
3.for(int i = 1; i <= n; ++i)
4.输入w[i]与v[i]
5.for(int j = w[i]; j <= c; ++j)
6.输出最大价值
3.1.2活动安排问题
输入:活动个数与活动时间
输出:活动安排
1.for(int i = 1; i <= n; ++i)
2.输入a[i].start与a[i]
3.对数组a进行排序sort(a,a+n,cmp)
4.for(i=0;i<n;i++)
5.for(int j = w[i]; j <= c; ++j)
6.if(a[i].start>=end)end=a[i].end
3.1.3找零钱问题
输入:需要找的零钱
输出:零钱
1.定义ins=0,零钱种类change[]={100,50,20,10,5,2,1}
2.while(n > 0)
3.ans = n/change[i]
4.if(ans!=0)
5.sum_ans = sum_ans + ans
6.n = n - ans * change[i]
3.1.4图着色问题
输入:颜色数m,无向图转化为矩阵;
输出:各个顶点的颜色数;
1.初始化各边关系和颜色;
2.循环直到所有顶点均涂色
2.1 取下种颜色k++;
2.2 依次考察所有顶点
2.2.1 若顶点i已着色,则转步骤2.2,考察下一个顶点;
2.2.2 若顶点i着颜色k不冲突,则color[i]=k;
3.输出各顶点着色情况
3.2程序代码
3.2.1.背包问题
#include <iostream>
using namespace std;
#define MAX 100
int max(int a,int b)
{
return a>b a:b;
}
int main()
{
int n, c;
int f[MAX][MAX]={0};
int w[MAX], v[MAX];
cout<<"输入物品个数和背包容量:"<<endl;
cin>>n>>c;
cout<<"输入物品重量和价值:"<<endl;
for(int i = 1; i <= n; ++i)
cin>>w[i]>>v[i];
for(int i = 1; i <= n; ++i)
{
for(int j = w[i]; j <= c; ++j)
{
f[i][j] = max(f[i-1][j], f[i-1][j-w[i]]+v[i]);
}j-w[i]的价值,因为放入所以背包容量减少了,价值增加了
}
cout<<"最大价值是:"<<f[n][c]<<endl;
return 0;
}
3.2.2.活动安排问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int start;
int end;
} a[11111];
bool cmp(node x,node y)
{
if(x.end<y.end) return true;
else if(x.end==y.end && x.start>y.start) return true;
return false;
}
int main()
{
int n,i,j,ans,end;
cin>>n;
for(i=0;i<n;i++) cin>>a[i].start>>a[i].end;
sort(a,a+n,cmp);
ans=0;
end=-1e9-100;
for(i=0;i<n;i++) {
if(a[i].start>=end) {
ans++;
end=a[i].end;
}
}
cout<<ans<<endl;
return 0;
}
3.2.3.找零钱问题
#include <stdio.h>
int Coin(double m)
{
printf("=====找零钱的方案为=====\n");
int ans = 0;
int n;
n = (int)(m*100);
int change[]={100,50,20,10,5,2,1};
int i = 0;
int sum_ans = 0; ;
while(n > 0)
{
ans = n / change[i];
if(ans != 0)
{
sum_ans = sum_ans + ans;
printf("需要找面额为%.2lf元的硬币个数为%d\n",1.0 * change[i] / 100, ans);
}
n = n - ans * change[i];
i++;
}
printf("需要找零的硬币总数为%d\n", sum_ans);
}
int main()
{
double n;
printf("请输入需要找给顾客的钱(单位:元、精确度为0.01):\n");
scanf("%lf",&n);
if((int)n*100 == 0)
{
printf("不需要找零钱\n");
}
else
{
Coin(n); //找零钱函数
}
return 0;
}
3.2.4.图着色问题
#include <iostream>
using namespace std;
#define n 5
static int arc[100][100];
static int color[100];
int Ok(int i)
{
for(int j=0; j<n; j++)
if(arc[i][j]==1 && color[i]==color[j])
return 0;
return 1;
}
void ColorGraph()
{
int k=0;
int flag=1; while(flag==1)
{
k++;
flag=0;
for(int i=0; i<n; i++)
{
if(color[i]==0)
{
color[i]=k;
if(!Ok(i))
{
color[i]=0;
flag=1;
}
}
int main()
{
cout<<"输入颜色的个数:";
int m;
cin>>m;
cout<<"输入无向图点和边的关系:"<<endl;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
{
int a;
cin>>a;
arc[i][j]=a;
}
ColorGraph();
cout<<"从1到5序号填色分别为:"<<endl;
for(int i=0; i<n; i++)
{
cout<<color[i]<<" ";
}
cout<<endl;
return 0;
}
四、运行结果及分析
4.1运行结果
4.1.1背包问题
时间复杂度:O(n) 4.1.2活动安排问题
时间复杂度:O(lg n)
4.1.3找零钱问题
时间复杂度:O(n)
4.1.4图着色问题
时间复杂度:O(n^2)
4.2分析
贪心法选择的是采用从顶向下、以迭代的方法做出相继选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择的性质,我们必须证明每一步所作的贪心选择最终能得到问题的最优解。通常可以首先证明问题的一个整体最优解,是从贪心选择开始的,而且作了贪心选择后,原问题简化为一个规模更小的类似子问题。然后,用数学归纳法证明,通过每一步贪心选择,最终可得到问题的一个整体最优解
五、实验小结
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。贪心算法是对所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
我们分析并解决了所有必做任务,并且对选做任务中的多个算法进行了分析。计算出来所做任务程序的时间复杂度。在实验过程中,在一些算法程序的设计过程中利用书本与互联网工具进行理解。并且通过网络工具获取一些算法分析。最后回归课本再次对贪心法的求解方式进行的更深入的理解,希望可以将该方法应用到实践当中,延伸到更广的范围中。