<*> 贪心算法并不是从整体最优上加以考虑, 而是从局部最优考虑, 每次总是做出当前看起来最好的选择,在某种意义上的局部最优选择;
<*> 最优子结构性质 :
<*>贪心选择性质:
1、 活动安排 :
问题描述 :设有n个活动集合E = {1 ,2,…,n} ,其中每个活动i都要求使用同一资源, 而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间Si和一个结束时间fi , 且Si < fi 。如果选择活动i ,则它在半开区间[Si , fi]内占用资源。若区间[Si,fi)与区间不相交,则称活动i和活动j是相容的, 也就是说Si >= fj || Sj >= fi 为真时 ,活动i和活动j是相容的。
要求:要在所给的活动集中选出最大的相容子集合;
code>>
#include
#include
#include
using namespace std;
class Activity
{
public :
int id;
int s;//活动开始时间
int f;//活动结束时间
public:
Activity()
{
cin >>this->s >> this->f;
}
friend void Arrange();
bool operator<(Activity &A1)
{
if (this->f < A1.f)
{
return true;
}
else
{
return false;
}
}
};
//活动集E:所给活动的集合
vector E;//竟然要加class
vector A;//相容标记集合
void Arrange()
{
sort(E.begin() + 1, E.end());//将活动按非减序列排列
int j = 0;
for (int i = 1; i < E.size(); i++)
{
if (E[i].s >= E[j].f)
{
A[i] = true;
j = i;
}
}
for (int i = 0; i < A.size(); i++)
{
if (A[i])
{
cout << E[i].id<<" ";
}
}
}
int main()
{
int n;//活动数量
cin >> n;
E.push_back(Activity());
E[0].s = 0;
E[0].f = 0;
for (int i = 1; i <= n; i++)
{
E.push_back(Activity());
E[i].id = E[i].s;
}
for (int i = 0; i <= n; i++)
{
A.push_back(false);
}
Arrange();
return 0;
}
2、 背包问题:
给定n种物品和一个背包。物品i的重量是wi ,其价值为vi,背包的容量为c , 问应该如何选择把哪一个物品装入背包中,使得装入背包中的物品的总价值最大?
0-1背包问题:不能部分装入物品,
背包问题:可选择装入部分物品
code>>
#include
#include
#include
#include
using namespace std;
class WP
{
public :
float w;
float p;
public :
WP(float w, float p)
{
this->w = w;
this->p = p;
}
bool operator<(WP wp)
{
if (1.0*w/p < 1.0*wp.w/wp.p)
{
return true;
}
else
{
return false;
}
}
};
class Knapsack
{
public :
vector wp;
int n;
float c;
public :
Knapsack()
{
cin >> this->n >> this->c;
wp.push_back(WP(0 , 0));
for (int i = 1; i <= n; i++)
{
int in1, in2;
cin>>in1>>in2;
wp.push_back(WP(in1, in2));
}
}
};
vector < float > x;
Knapsack ks;
void GreedyKP()
{
x.push_back(0);
sort(ks.wp.begin() + 1, ks.wp.end());
int sum = 0;
int i;
for (int i = 1; i < ks.n; i++)
{
x.push_back(0);
}
for (i = 1; i <= ks.n; i++)
{
if (ks.wp[i].w < ks.c)
{
x[i] = 1;
ks.c -= ks.wp[i].w;
}
else
{
break;
}
}
if (i < ks.n + 1)
{
x.push_back(1.0*ks.c/ks.wp[i].w);
}
for (int i = 1; i < x.size(); i++)
{
cout << ks.wp[i].w << " : " <
3、 最优装载 :
问题描述:有一批集装箱要装上载重量为c的轮船。其中集装箱i的重量为wi , 最优装载问题要求在装载体积不受限制的情况下,将尽可能多的集装箱装上船;
code>>
#include
#include
#include
#include
using namespace std;
//最优装载问题
class Loading
{
public :
vector w;
float c;
int n;
public :
Loading()
{
cin >> this->n >> this->c;
w.push_back(0);
for (int i = 1; i <= this->n; i++)
{
float in1;
cin >> in1;
this->w.push_back(in1);
}
}
};
vector x;
Loading L = Loading();
void Load()
{
sort(L.w.begin()+1, L.w.end());
for (int i = 0; i <= L.n; i++)
{
x.push_back(0);
}
for (int i = 1; i < L.n; i++)
{
if (L.w[i] <= L.c)
{
x[i] = 1;
L.c -= L.w[i];
}
else
{
break;
}
}
for (int i = 1; i <= L.n; i++)
{
if (x[i] == 1)
{
cout.precision(4);
cout << "weght : " << L.w[i] << endl;
}
}
}
int main()
{
Load();
return 0;
}
4、 哈弗曼编码 :
问题描述:
code>>
Huffman.cpp
#include"BinaryTree.h"
#include
#include
#include
#include
using namespace std;
typedef BinaryTree HuffmanTree;
typedef BinaryNode HuffmanNode;
class FC
{
public :
float m_f;
char m_c;
public :
FC(float f = 0 , char c = ' ')
{
m_f = f;
m_c = c;
}
bool operator==(float f)
{
if (m_f == f)
{
return true;
}
else
{
return false;
}
}
};
class Huffman
{
public :
Huffman()
{
cin >> n;
fc.push_back(FC());
fc[0].m_f = 10000;
for (int i = 1; i <= n; i++)
{
float in1;
char in2;
cin >> in1;
cin >> in2;
fc.push_back(FC(in1, in2));
}
//生成单结点树
for (int i = 0 ; i <= n; i++)
{
HuffmanTree z;
z.MakeTree(fc[i].m_f , HuffmanTree() , HuffmanTree());
HT.push_back(z);
}
}
public :
int n;//字符总数
vector fc;//字符出现的频率表
vector HT;
};
Huffman huff = Huffman();
vector code;
//构建哈弗曼树
HuffmanTree MakeHuffmanTree()
{
//建优先级队列
priority_queue> Q;
for (int i = 0; i <= huff.n; i++)
{
Q.push(huff.HT[i]);
}
for (int i = 1; i < huff.n; i++)
{
HuffmanTree x, y ,z;
x = Q.top();
Q.pop();
y = Q.top();
Q.pop();
float w = x.m_root->m_data + y.m_root->m_data;
z.MakeTree(w , x , y);
Q.push(z);
}
return Q.top();
}
//生成编码
void Huffmancode(HuffmanNode* root)
{
if (root != NULL)
{
if (root->m_pleft == NULL && root->m_pright == NULL)
{
vector::iterator iter = find(huff.fc.begin() + 1, huff.fc.end(), root->m_data) ;
cout << iter->m_c <<"的编码 : ";
for (int i = 1; i < code.size(); i++)
{
cout << code[i];
}
cout << endl;
}
if (root->m_pleft != NULL)
{
code.push_back(0);
Huffmancode(root->m_pleft);
}
if (root->m_pright != NULL)
{
code.push_back(1);
Huffmancode(root->m_pright);
}
}
code.pop_back();
}
//译码
void Interpret(vector s , HuffmanNode* root)
{
HuffmanNode* p = root;
for (int i = 0; i < s.size(); i++)
{
if (NULL == p->m_pleft && NULL == p->m_pright)
{
vector::iterator iter = find(huff.fc.begin() + 1, huff.fc.end(), p->m_data);
cout << iter->m_c;
p = root;
}
if (0 == s[i])
{
p = p->m_pleft;
}
if (1 == s[i])
{
p = p->m_pright;
}
}
cout << endl;
}
int main()
{
HuffmanTree htree;
htree = MakeHuffmanTree();
code.push_back(-1);
Huffmancode(htree.m_root);
vector scode;
char in;
while ((in = getchar()) != '#')
{
scode.push_back(in-48);
}
//前提Huffman树已建立
Interpret(scode , htree.m_root);
return 0;
}
//上面用到的二叉树头文件BinaryTree.h
#include
//定义结点类型
template
class BinaryTree;//预引用
template
class BinaryNode
{
public:
BinaryNode() :m_pleft(NULL), m_pright(NULL) {};//无参构造函数
BinaryNode(Type item, BinaryNode *pleft = NULL, BinaryNode *pright = NULL) :m_data(item), m_pLeft(pleft), m_pright(pright) {};//含参构造函数
//friend
//friend class BinaryTree;
public :
BinaryNode *m_pleft, *m_pright;
Type m_data;
};
//定义二叉树
template
class BinaryTree
{
public:
BinaryTree() : m_root(NULL){ };
void MakeTree(Type item, BinaryTree LBTree, BinaryTree RBTree )
{
m_root = new BinaryNode();
m_root->m_data = item;
m_root->m_pleft = LBTree.m_root;
m_root->m_pright = RBTree.m_root;
}
friend bool operator<(BinaryTree BT1 , BinaryTree BT2)
{
if (BT1.m_root->m_data < BT2.m_root->m_data)
{
return false;
}
else
{
return true;
}
}
public:
BinaryNode *m_root;
};
code>>
#include
#include
#include
using namespace std;
class JOB
{
public :
JOB()
{
cin >> n >> m;
jt.push_back(0);
mt.push_back(0);
for (int i = 1; i <= n; i++)
{
int in1;
cin >> in1;
jt.push_back(in1);
}
for (int i = 1; i <= m; i++)
{
mt.push_back(0);
}
};
public :
int n, m;
vector jt;
vector mt;
};
struct greater
{
bool operator()(int x , int y) const
{
return (x > y);
}
};
JOB J;
void greedyJOB()
{
sort(J.jt.begin() + 1, J.jt.end() , greater());
int i;
vector::iterator iter;
for (i = 1; i <= J.n; i++)
{
if (i <= J.m)
{
J.mt[i] += J.jt[i];
}
else
{
iter = min_element(J.mt.begin() + 1, J.mt.end());
*iter += J.jt[i];
}
}
iter = max_element(J.mt.begin() + 1, J.mt.end());
cout << *iter << endl;
}
int main()
{
greedyJOB();
return 0;
}
6、 Kruskal算法:
code>>
#include"UnionSet.h"
#include
#include
#include
#include
using namespace std;
class Edge
{
public :
Edge(int i = -1, int j = -1, int weight = 1000)
{
this->i = i;
this->j = j;
this->weight = weight;
}
friend bool operator<(Edge E1 , Edge E2)
{
return (E1.weight >= E2.weight);
}
public:
int i, j;
int weight;
};
class Graph
{
public :
Graph()
{
cin >> vn >> en;
edges.push_back(Edge());
for (int i = 1; i <= en; i++)
{
int in1, in2, in3;
cin >> in1 >> in2 >> in3;
edges.push_back(Edge(in1, in2, in3));
}
}
public :
vector edges;//边集
int vn;//顶点数
int en;//边数
};
Graph G;
vector minspt;//存储最小生成树中各边
//克鲁斯卡尔算法
void Kruskal()
{
priority_queue> Q(G.edges.begin()+1 , G.edges.end());
/*Q.push(Edge());
for (int i = 1; i <= G.en; i++)
{
Q.push(G.edges[i]);
}
*/
//初始化并查集
vector S;
S.push_back(PNode());
for (int i = 1; i <= G.vn; i++)
{
S.push_back(PNode(i, i));
}
UnionSet U = UnionSet(S , G.vn);
//边长递增序依次考察每条边
Edge s1;
vector::iterator a ,b;
for (int i = 1; i <= G.en; i++)
{
s1 = Q.top();
Q.pop();
a = U.Find(s1.i);//s1.i所在集合的头
b = U.Find(s1.j);//s2.j所在集合的头
if (a->data != b->data)
{
minspt.push_back(s1);
U.Union(a->data, b->data);
}
}
}
int main()
{
Kruskal();
cout << "minimum_spanning_Tree : " << endl;
for (int i = 0; i < minspt.size(); i++)
{
cout<<"( " << minspt[i].i <<" , " <>上面用到的并查集:
#pragma once
#include
#include
#include
using namespace std;
class PNode
{
public:
PNode(int d = -1, int p = -1)
{
data = d;
parent = p;
};
bool operator==(int val)
{
return (data == val);
}
public:
int data;
int parent;//存在父子关系的就在同一个连通分支,parent是自己的结点,他就是该集合的代表;
};
class UnionSet
{
public:
UnionSet()//初始化集合
{
cin >> n;
s.push_back(PNode(0, 0));
for (int i = 1; i <= n; i++)
{
int in1;
int in2;
cin >> in1 >> in2;
s.push_back(PNode(in1, in2));
}
};
UnionSet(vector s, int n)
{
this->s = s;
this->n = n;
};
void Union(int s1, int s2)
{
//合并成员s1, s2所在的两个连通分支
/*vector::iterator iter1, iter2;
iter1 = Find(s1);
iter2 = Find(s2);
if(iter1->data != iter2->data)
{
iter2->parent = iter1->data;
}*/
//合并代表s1 , s2所在的连通分支
vector::iterator iter1, iter2;
iter1 = find(s.begin() + 1, s.end(), s1);
iter2 = find(s.begin() + 1, s.end(), s2);
iter2->parent = iter1->data;
};
vector::iterator Find(int m)//查找成员m所在集合的代表,返回它的位置
{
vector::iterator iter , p , q , r;
iter = find(s.begin() + 1, s.end(), m);
//路径压缩
p = iter;
while (p->parent != p->data)
{
p = find(s.begin() + 1, s.end(), p->parent);//返回代表的位置
}
r = iter;//指向当前
q = find(s.begin() + 1, s.end(), r->parent);//指向上级
while (q != p)
{
r->parent = p->parent;
r = q;//上位
q = find(s.begin() + 1, s.end(), q->parent);//上位
}
return p;//返回树根,即代表
}
public :
vector s;
int n;
};
7、 Prim算法:
code>>感觉写复杂了。。。。。。
#include
#include
#include
using namespace std;
class EdgeNode
{
public :
EdgeNode(int i = 0 , int j = 0 , int w = 10000)
{
this->i = i;
this->j = j;
this->weight = w;
}
friend bool operator==(EdgeNode E1 , EdgeNode E2)
{
return ((E1.i == E2.i && E1.j == E2.j) || (E1.i == E2.j && E1.j == E2.i));
}
public :
int i, j;
int weight;
};
class Graph
{
public :
Graph()
{
cin >> vn >> en;
edges.push_back(EdgeNode());
for (int i = 1; i <= en; i++)
{
int in1, in2, in3;
cin >> in1 >> in2 >> in3;
edges.push_back(EdgeNode(in1, in2, in3));
}
minspt.push_back(EdgeNode());
}
EdgeNode Find(int i, int j)
{
EdgeNode e = EdgeNode(i, j, 0);
vector::iterator iter;
iter = find(edges.begin() + 1, edges.end(), e);
if (iter != edges.end())
{
return EdgeNode(i, j, iter->weight);
}
else
{
return EdgeNode(i, j, 10000);
}
}
public :
int vn, en;
vector edges;
vector minspt;
};
Graph G;
vector closest;//closest[i] : 从V-S中的顶点i到S中最近的j顶点的相应的边
vector s;//已选择的顶点标记为true;
bool comp(EdgeNode E1 ,EdgeNode E2 )//E1 类似扫描器p, E2类似min
{
if (!s[E1.i])
{
return (E1.weight < E2.weight);
}
else
{
return false;
}
}
void prim()
{
EdgeNode e1, e2;
vector::iterator iter;
closest.push_back(EdgeNode());
//初始化closest , s;
for (int i = 0; i <= G.vn; i++)
{
s.push_back(false);
}
s[0] = s[1] = true;
for (int i = 1; i <= G.vn; i++)//到1的最近边
{
if (!s[i])
{
e1 = G.Find(i, 1);
closest.push_back(EdgeNode(i, 1, e1.weight));
}
else
{
closest.push_back(EdgeNode());
}
}
for (int j = 1; j < G.vn; j++)
{
int k = 0;
iter = min_element(closest.begin() + 1, closest.end(), comp);
k = iter->i;
if (k)
{
s[k] = true;//顶点k加入S中
G.minspt.push_back(*iter);
//修改closet
for (int i = 1; i <= G.vn; i++)
{
if (!s[i])
{
e1 = G.Find(i, closest[i].j);
e2 = G.Find(i, k);
if (e1.weight > e2.weight)//i到S中的新加的顶点k更近,更新closest
{
closest[i] = e2;
}
}
}
}
}
}
int main()
{
prim();
cout << "minimum_spanning_Tree : " << endl;
for (int i = 1; i <= G.minspt.size()-1; i++)
{
cout << "( " << G.minspt[i].j << " , " << G.minspt[i].i << " , " << G.minspt[i].weight << " )" << endl;
}
return 0;
}