局部最优,只图眼前利益,但是局部最优之和一般不会是全局最优,但也不一定,比如最小生成树:prim和Kruscal算法还有最短路径迪杰斯特拉,都是超级优秀的贪心算法的应用。
还有分饼干问题以及0-1背包问题,都是想着局部最优,在0-1背包问题中,想着重量最优先活着价值最优先往往都得不到全局最优解,但是价值率最优的话可以达到,通常情况下。
注意,这里与图不一样的地方就是增加了一个结构closedge,去保存V中每个点与与已经选择的U中点之间的最小距离以及与U中那个点相连。但是我把它结构直接变换成为Graph里的vexs数组了,嘿嘿
题目:
假设有A,B,C,D,E 5个村庄要修路使每个村子都有路连接(A->B->C也算A,C相连),但是要修路的总长度最小.
#include
#include
#include
#include
using namespace std;
#define MAXNUM 100
//假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
//最小生成树问题,
int sum = 0;
typedef struct //在prim中特存的
{
char data;
int adjvex;
int lowcost;
}Closedge[MAXNUM];
typedef struct AMGraph
{
int arcs[MAXNUM][MAXNUM];
Closedge closedge;
int arcnum;
int vexnum;
}AMGraph;
int AMLocate(AMGraph* Graph, char n)
{
for (int i = 0; i < Graph->vexnum; i++)
{
if (n == Graph->closedge[i].data)
{
return i;
break;
}
}
return -1;
}
void CreatGraph(AMGraph* Graph)
{
cout << "请输入顶点数、边数:" << endl;
cin >> Graph->vexnum >> Graph->arcnum;
cout << "请输入顶点的值" << endl;
for (int i = 0; i < Graph->vexnum; i++)
{
cin >> Graph->closedge[i].data;
}
for (int i = 0; i < Graph->vexnum; i++)
{
for (int j = 0; j < Graph->vexnum; j++)
{
Graph->arcs[i][j] = MAXNUM;
}
}
cout << "请依次输入各个边的顶点以及值" << endl;
for (int i = 0; i < Graph->arcnum; i++)
{
char x1, x2;
int dis, n, m;
cin >> x1 >> x2 >> dis;
n = AMLocate(Graph, x1);
m = AMLocate(Graph, x2);
Graph->arcs[n][m] = dis;
Graph->arcs[m][n] = dis;
}
}
int fingMin(AMGraph* Graph)
{
int min, temp = 0;
min = MAXNUM;
for (int i = 0; i < Graph->vexnum; i++)
{
if (Graph->closedge[i].lowcost != 0 && Graph->closedge[i].lowcost < min)
{
min = Graph->closedge[i].lowcost;
temp = i;
}
}
return temp;
}
void Updata(AMGraph* Graph,int min)
{
for (int i = 0; i < Graph->vexnum; i++)
{
if (Graph->closedge[i].lowcost > Graph->arcs[min][i])
{
Graph->closedge[i].lowcost = Graph->arcs[min][i];
Graph->closedge[i].adjvex = min;
}
}
}
void Prim(AMGraph* Graph,char sta)
{
int start = AMLocate(Graph, sta);
if (start != -1) //从该点开始;
{
for (int i = 0; i < Graph->vexnum; i++)
{
Graph->closedge[i].adjvex = start;
Graph->closedge[i].lowcost = Graph->arcs[start][i];
}
Graph->closedge[start].lowcost = 0;
sum++;
while (sum < Graph->vexnum)
{
int min = fingMin(Graph);
int u0, v0;
u0 = Graph->closedge[min].adjvex;
v0 = min;
cout << Graph->closedge[u0].data << "-->" << Graph->closedge[v0].data << endl;
Graph->closedge[min].lowcost = 0;
sum++;
Updata(Graph, min);
}
}
}
int main()
{
AMGraph* Graph = new AMGraph;
CreatGraph(Graph);
// 假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
char start = 'A';
Prim(Graph, start);
return 0;
}
跟上面同样的题目!
写这个算法的时候,自己由于大意,找了很久错误,最后发现复制的时候老是忘记改掉该改的值,很不好的习惯,还有就是复制运算=老是写成==,最后就是这个问题增加了一个辅助的数据结构是Edges,描述每一条边,因为虽然找的时候是按边从小到大找,但是会存在变=边的值比较小但是加入后形成环的现象,所以需要再加一个数组表示每个顶点在哪个连通分量中,相同连通分量的不可以加入了,说明他们已经在了。
#include
#include
#include
#include
using namespace std;
#define MAXNUM 100
//假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
//最小生成树问题,
int sum = 0;
int VesSet[MAXNUM];
typedef struct //在prim中特存的
{
char data;
int adjvex;
int lowcost;
}Closedge[MAXNUM];
typedef struct Edges
{
int Head;
int Tail;
int lowcost;
}Edges,edge;
Edges* Edge;
typedef struct AMGraph
{
int arcs[MAXNUM][MAXNUM];
Closedge closedge;
int arcnum;
int vexnum;
}AMGraph;
int AMLocate(AMGraph* Graph, char n)
{
for (int i = 0; i < Graph->vexnum; i++)
{
if (n == Graph->closedge[i].data)
{
return i;
break;
}
}
return -1;
}
void CreatGraph(AMGraph* Graph)
{
cout << "请输入顶点数、边数:" << endl;
cin >> Graph->vexnum >> Graph->arcnum;
cout << "请输入顶点的值" << endl;
for (int i = 0; i < Graph->vexnum; i++)
{
cin >> Graph->closedge[i].data;
VesSet[i] = i;
}
for (int i = 0; i < Graph->vexnum; i++)
{
for (int j = 0; j < Graph->vexnum; j++)
{
Graph->arcs[i][j] = MAXNUM;
}
}
cout << "请依次输入各个边的顶点以及值" << endl;
Edge = new Edges[Graph->arcnum + 1];
for (int i = 0; i < Graph->arcnum; i++)
{
char x1, x2;
int dis, n, m;
cin >> x1 >> x2 >> dis;
n = AMLocate(Graph, x1);
m = AMLocate(Graph, x2);
Graph->arcs[n][m] = dis;
Graph->arcs[m][n] = dis;
Edge[i].Head = n;
Edge[i].Tail = m;
Edge[i].lowcost = dis;
}
}
int pivoky(Edges* Edge,int low,int high)
{
int pivock = Edge[low].lowcost;
Edges temp = Edge[low];
while (low < high)
{
while (low < high && Edge[high].lowcost >= pivock)
high--;
Edge[low] = Edge[high];
while (low < high && Edge[low].lowcost <= pivock)
low++;
Edge[high] = Edge[low];
}
Edge[high] = temp;
return high;
}
void QuickSort(Edges* Edge, int low, int high)
{
if (low < high)
{
int pivocy = pivoky(Edge, low, high);
QuickSort(Edge, low, pivocy - 1);
QuickSort(Edge, pivocy + 1, high);
}
}
void Kruscal(AMGraph* Graph)
{
QuickSort(Edge, 0, Graph->arcnum - 1);
int u0, v0;
for (int i = 0; i < Graph->arcnum; i++)
{
u0 = Edge[i].Head;
v0 = Edge[i].Tail;
int set = VesSet[v0];
if (VesSet[u0] != VesSet[v0])
{
cout << Graph->closedge[u0].data << "-->" << Graph->closedge[v0].data << endl;
for (int j = 0; j < Graph->vexnum; j++)
{
if (VesSet[j] == set)
VesSet[j] = VesSet[u0]; //合并分量
}
}
}
}
int main()
{
AMGraph* Graph = new AMGraph;
CreatGraph(Graph);
// 假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
//char start = 'A';
//Prim(Graph, start);
Kruscal(Graph);
return 0;
}
还是最初的那一题。
总结:
由于太累了,输出就简化一下,倒着输出了。
这个算法写出来之后给我的感觉就是,不可以一味地凭着感觉来,我在最初将每次计算出最短路径的点的D[i]的值直接置为了0,想让它代替S的作用,但是实际上并不行,与Prim算法不同的是,在这里强调从某个点出发到其余各点的最短路径,故每次计算更新时都需要用到已经求得的最短路径,如果将它们的D[i]置为0,则会导致整个算法错误。
这些算法看着跟自己敲出来还是不一样的,所以自己多想。
#include
#include
#include
#include
using namespace std;
#define MAXNUM 100
int D[MAXNUM];
int path[MAXNUM];
bool S[MAXNUM];
typedef struct //在prim中特存的
{
char data;
int adjvex;
int lowcost;
}vexsnumal;
typedef struct AMGraph
{
int arcs[MAXNUM][MAXNUM];
char vexs[MAXNUM];
int arcnum;
int vexnum;
}AMGraph;
int AMLocate(AMGraph* Graph, char n)
{
for (int i = 0; i < Graph->vexnum; i++)
{
if (n == Graph->vexs[i])
{
return i;
break;
}
}
return -1;
}
void CreatGraph(AMGraph* Graph)
{
cout << "请输入顶点数、边数:" << endl;
cin >> Graph->vexnum >> Graph->arcnum;
cout << "请输入顶点的值" << endl;
for (int i = 0; i < Graph->vexnum; i++)
{
cin >> Graph->vexs[i];
S[i] = false;
}
for (int i = 0; i < Graph->vexnum; i++)
{
for (int j = 0; j < Graph->vexnum; j++)
{
Graph->arcs[i][j] = MAXNUM;
}
}
cout << "请依次输入各个边的顶点以及值" << endl;
for (int i = 0; i < Graph->arcnum; i++)
{
char x1, x2;
int dis, n, m;
cin >> x1 >> x2 >> dis;
n = AMLocate(Graph, x1);
m = AMLocate(Graph, x2);
Graph->arcs[n][m] = dis;
Graph->arcs[m][n] = dis;
}
}
int fingMin(AMGraph* Graph)
{
int min, temp = 0;
min = MAXNUM;
for (int i = 0; i < Graph->vexnum; i++)
{
if (min > D[i] && S[i] !=true)
{
min = D[i];
temp = i;
}
}
return temp;
}
void Update(AMGraph* Graph,int min)
{
for (int i = 0; i < Graph->vexnum; i++)
{
if (D[min] + Graph->arcs[i][min] < D[i])
{
D[i] = D[min] + Graph->arcs[i][min];
path[i] = min;
}
}
}
void Dijkstra(AMGraph *Graph,char sta)
{
int sum = 1;
int start = AMLocate(Graph, sta);
for (int i = 0; i < Graph->vexnum; i++)
{
D[i] = Graph->arcs[start][i];
if (Graph->arcs[i][start] != MAXNUM)
path[i] = start;
else
path[i] = -1;
}
D[start] = 0;
S[start] = true;
path[start] = 0;
//cout << sta << "-->";
while (sum < Graph->vexnum)
{
int min = fingMin(Graph);
S[min] = true;
Update(Graph,min);
sum++;
}
}
int main()
{
AMGraph* Graph = new AMGraph;
CreatGraph(Graph);
char sta = 'A';
int start = AMLocate(Graph,sta);
Dijkstra(Graph, sta);
for (int i = 0; i < Graph->vexnum; i++)
{
if (Graph->vexs[i] != sta)
{
cout << Graph->vexs[i] << "<--";
int pre = path[i];
while (pre != 0)
{
cout << Graph->vexs[pre] << "<--";
pre = path[pre];
}
cout << Graph->vexs[start] << endl;
}
}
return 0;
}