贪心算法采用自顶向下的方法,如此问题中n个活动,我们首先安排第一个活动,并判断下一个活动哪一个的开始时间与第一个活动的结束时间匹配。所以贪心算法总是第一步就做出选择。
给个伪代码:
template
void GreedySelector(int n, Type s[], Type f[], bool A[])
{
A[1] = true; //安排活动1号
int j = 1;
for (int i = 2;i <= n;i++) {
if (s[i] >= f[j]) { //判断后一个活动是否与前一个活动的时间匹配
A[i] = true; //安排i号
j = i;
}
else
A[i] = false; //不安排i号
}
}
源代码:
#include
using namespace std;
void GreedySelector(int s[],int f[],int n){
int j=0;
cout<<"安排活动1"<=f[j]){
cout<<"安排活动"<
这里的背包问题和01背包问题不同点在于:物品 i 可以拆分,所以背包肯定可以装满,因为不可能有背包有空间冗余而装不进的说法。
这个问题极其简单,因为物品可以拆,所以我们一开始就放价值最大的(贪心选择)。
伪代码:
template
void Knapsack(int n,Type M,Type v[],Type w[],Type x[])
{
Sort(n,v,w); //以单位重量的价值从高到低排序
int i;
for (i = 1;i <= n;i++) x[i] = 0;
Type c = M; //初始容量c
for (i = 1;i <= n;i++) {
if (w[i] > c) break; //放不下
x[i] = 1; //放入i物品
c -= w[i]; //容量中减去i物品的重量
}
if (i <= n)
x[i] = c / w[i]; // 剩下的空间用最后i物品部分填满
}
与背包问题类似,一艘船上需要装载最多箱子,则我们从重量最小的开始装(贪心选择)
伪代码:
template
void Loading(int x[], Type w[], Type c, int n)
{
int *t = new int [n+1];
Sort(w, t, n); //以重量从小到大排序
for (int i = 1; i <= n; i++) x[i] = 0; //初始化
for (int i = 1; i <= n && w[t[i]] <= c; i++) {x[t[i]] = 1; c -= w[t[i]];} //一箱一箱放进船
}
同样我们总是从结点1开始,每次寻找路径最小的分支。
这里使用Prim算法
源代码:
#include
using namespace std;
#define inf 0x3f3f3f3f
void Prim(int c[][10],int n){
int lowcost[10];
int closest[10];
bool s[10];
s[1] = true;
for(int i = 2;i<=n;i++){
lowcost[i] = c[1][i];
closest[i] = 1;
s[i] = false;
}
for(int i = 1;i>n;
cout<<"请输入所有对顶点及其权值"<>a>>b>>w;
c[a][b]=w;
c[b][a]=w;
}
Prim(c,n);
return 0;
}
我认为这与01背包问题和最小生成树有相似之处。首先我们也从第一个节点寻找路径最短的分支,不过其中除了需要判断每个节点的最短路径,还需要考虑选取此路径是否为最优。
使用Dijkstra算法
给出源代码:
#include
using namespace std;
#define INF 0x3f3f3f3f
int c[6][6]={
INF,INF,INF,INF,INF,INF,
INF,INF,10,INF,30,100,
INF,INF,INF,50,INF,INF,
INF,INF,INF,INF,INF,10,
INF,INF,INF,20,INF,60,
INF,INF,INF,INF,INF,INF
}; //这里表示一个有向图,其中的值为权
void Dijkstra(int n,int v){
int dist[n+1];//记录到顶点的最短路径长度
int prev[n+1];//记录最短路径的前后顶点
bool s[n+1];
for(int i = 1;i <= n;i++){
dist[i] = c[v][i];
s[i] = false;
if(dist[i] == INF)
prev[i] = 0;
else
prev[i] = v;
}
dist[v] = 0;
s[v] = true;
for(int i = 1;i <= n;i++){
int temp = INF;
int u = v;
for(int j = 1;j <= n;j++){
//到顶点 j 的路径可走且为最短,将最短的路径赋给dist[j]
if((!s[j]) && (dist[j] < temp)){
temp = dist[j];
u = j;
}
}
s[u] = true;
for(int j = 1;j <= n;j++){
//如果到顶点 j 的路径可以通过上一顶点 u 的路径 加上另一条路使其更短,将这条更短的路径赋给dist[j]
if((!s[j]) && (c[u][j] < INF)){
if(dist[u] + c[u][j] < dist[j]){
dist[j] = dist[u] + c[u][j];
prev[j] = u; //将上一个顶点 u 记录在prev[]中
}
}
}
}
for(int i = 2;i <= n;i++){
int j = i;
cout<<"顶点"<
一辆汽车加满油后可以行驶 n km,路途中有 k 个加油站,a[i]表示第 i 个加油站到下一个加油站的距离,其中a[0]表示出发点到第一个加油站的距离,a[k]表示最后一个加油站到终点的距离。求从起点到终点最少加油次数。
对于给定所有距离,我们总是从起点出发寻找加油点,所以运用贪心选择。
源代码:
#include
using namespace std;
void func(int a[],int n,int k){
int result = 0,m = n;
if(a[k]>n){
cout<<"No Solution!"<>n>>k;
for(int i = 0;i<=k;i++){
cin>>a[i];
}
func(a,n,k);
return 0;
}