#include<stdio.h>
#include<stdlib.h>
//贪心算法
/*
特点:局部最优解也是全局最优解。
通过不断的求解局部最优解来求出全局最优解
注:邻接矩阵结构体创建
*/
//prim
/*
先随便从图中选取一条边,然后将该边到其他边的距离进行排序,选择最小的一条边(局部最优解),该边一定是
最小生成树的一部分,然后通过原顶点到边距离和新顶点到边的距离对比,更新新顶点到其他顶点的距离,循环此过程。
注:
1 表需要初始化
2 如何输出:找到之后打印即可
*/
#define n 8
typedef struct graph {
int edge[n][n];
int vex[n];
}graph;
void prim(graph g) {
int weight[n];//该点到i的最小权值
int adjvex[n];//由谁指出到i
int m, i, j, k;
for (i = 0; i < n; i++) {
adjvex[i] = 0;
weight[i] = g.edge[0][i];
}
for (m = 0; m < n; m++) {
int minweight = 999;
for (i = 0; i < n; i++) {
if (weight[i] < minweight) {
minweight = weight[i];
k = i;//k是找到的最小权值点
}
}
weight[k] = 0;
for (j = 0; j < n; j++) {
if (g.edge[k][j] < weight[j]) {
weight[j] = g.edge[k][j];//后浪优于前浪
adjvex[j] = k;//谁是后浪
}
}
}
}
// kruskal
/*
方法:在图中依次选取不构成环的最小权值边,最终组成最小生成树
关键:判断环,使用并查集来判断
并查集算法:
合并:使用parent数组对结点进行组成树
检查:分别找到两个结点的根,如果根不是同一个,则不构成环,反之构成环,
注意:
1 union过程就是构建最小生成树过程,找根节点对比才是判断过程
*/
void init(int parent[], int rank[]) {
for (int i = 0; i < n; i++) {
parent[i] = -1;
rank[i] = 0;
}
}
int findroot(int parent[], int x) {
while (parent[x] != -1)
x = parent[x];
return x;
}
void unionfunc(int parent[], int rank[], int x, int y) {
if (rank[x] > rank[y]) {
parent[y] = x;
}
else if (rank[x] < rank[y])
parent[x] = y;
else {
parent[x] = y;
rank[y]++;
}
}
void kruskal(graph g, int parent[], int rank[]) {
int i, j, k, m = 1;
for (i = 0; i < n; i++) {
int minweight = 999;
for (j = 0; j < n; j++)
if (g.edge[i][j] < minweight)
minweight = g.edge[i][j];
init(parent, rank);
int xroot = findroot(parent, i);
int yroot = findroot(parent, j);
if (xroot != yroot) {
unionfunc(parent, rank, i, j);
printf("第%d条边(%d,%d)\n", m, i, j);
m++;
}
}
}
//dijkstra
/*
算法描述:单源最短路径问题,找到0点到其他所有点的最短路径,类似prim,需要更新最短路径和点集合
本质就是以0点位基础点生成的最小生成树上,0点到其他点的路径集合。
首先找到0点到其他点的最短路径,然后将新结点加入最短路径点集合,计算0到新结点最短路径+新结点到其他点最短路径
和0点到其他点最短路径进行比较,更新d[]表
注:
1 不需要w[n][n],直接用g.edge[i][j]就可以
2 S[i]防止重复找已经加入最短路径的顶点
3 dijkstra算法和prim算法的区别就是dijkstra算法只需要更新一个表d[i](民weight[i])即可
*/
int d[n];//0点到i点的最短路径,存放该算法的输出结果
int S[n];//标记找到的最短路径点
void dijkstra(graph g, int s) {
int i, j, k;
for (i = 0; i < n; i++) {
d[i] = g.edge[0][1];
}
S[0] = s;
int minedge;
for (int m = 0; m < n; m++) {
for (i = 0; i < n; i++)
minedge = 99;
if (d[i] != -1 && d[i] < minedge) {
minedge = d[i];
k = i;
}
S[k] = 1;
for (j = 0; j < n; j++) {
if (!S[k] && g.edge[k][j] + d[k] < d[j])
d[j] = g.edge[k][j] + d[k];
}
}
}
//加油站算法:有n个加油站,汽车加一次油可以行驶k公里,给定各个加油站之间距离,求达到目的地的最少加油次数
/*
分析:
贪心策略:加一次油,行驶最远的距离,再加油,也就是减少油的浪费。
由于不能使得车子停在加油站之间,因此需要考虑车子内的油最多能行使几个加油站,还有剩余
局部最优解就是每次行驶的最长距离,全局最优解就是这些距离的和
*/
int k[n - 2];//各个加油站之间的距离
void gas(int left, int y) {
int i = 1, j, sum = 0;
printf("应该选择的加油站点编号为:\n");
while (left >= 0) {
int x = y;
while (x > 0) {
x -= k[i];
left -= k[i];
i++;
}
i--;
left += k[i];
printf("%d ", i);
sum++;
}
printf("总共加油%d次", sum);
}
//砝码最小代价问题(不是真题)
int chip(int data[]) {
int length = sizeof(data) / sizeof(data[0]);
int k=0, l=0;
for (int i = 0; i < length; i++) {
if (data[i] % 2 == 0)
k++;
else l++;
}
if (l > k)
return l - k;
else return k - l;
}
//判断子序列
void issubsequence(char a[], char b[]) {
int i = 0,j=0;
while (a[i]!='\0'&&b[j] != '\0') {
if (a[i + 1] == '\0' && a[i] == a[j])
break;
else if (a[i] == b[j])
i++;
j++;
}
if (a[j] == '\0')
printf("flase");
else printf("true");
}
//兑酒算法
int exchangewine(int n, int exchange) {
return (n * exchange - 1)/ (exchange - 1);
}
//载客算法:哈希表
int car(int** trips, int size,int c) {
int miles[1001] = { 0 };
int passenger, start, end;
for (int i = 0; i < size; i++) {
passenger = trips[i][0];
start = trips[i][1];
end = trips[i][2];
miles[start] += passenger;
miles[end] -= passenger;
}
int n = 0;
for (int i = 0; i <= 1000; i++) {
n += miles[i];
if (n > c)
return false;
}
return true;
}
//纸币找零问题
int money(int sum,int n) {
int a[] = { 4,0,2,7,1,2, };
int b[] = { 1,2,5,10,20,50,100 };
int num=0,temp=0;
n -= 1;
while (sum!= 0) {
if (a[n] > (sum / b[n])) {
num += sum / b[n];
sum %= b[n];
}
else {
num += a[n];
sum -= a[n] * b[n];
}
n--;
}
return num;
}
//最小乘船数问题:船170 人:110 100 50 40 30
void minboat() {
int max, num,k,s[10],n,m;
scanf_s("%d%d", &max, &num);
int a[10];
for (int i = 0; i < num; i++) {
scanf("%d", &a[i]);
}
heapsort(a);
k = 0,n=num;
while(n!=0){
m = max;
for (int j = 0; j < n; j++) {
if (a[j] < m && s[j] == 0) {
s[j] == 1;
n--;
m -= a[j];
}
}
k++;
}
return k;
}
int boat(int k) {
}
#define m 10
int poke() {
int a[n],b[m*n-n],sum;
for (int i = 0; i < n; i++)
scanf_s("%d", &a[i]);
for (int j = m*n, i = 0,k=0; k<m*n-n; j--,k++) {
if (j != a[i])
b[k] = j;
else {
if(i<n-1)
i++;
}
}
for (int i = 0; i < n; i++) {
if (b[i] < a[i])
sum++;
}
return sum;
}
//4.5坐标轴种树,满足所有方案
int tree() {
int num, h;
scanf("%d", num);
int i,j;
int ans[100] = {0};
int a, b, t;
int sum;
int ma=999, mb=-1;
for (i = 0; i < h; i++) {
scanf("%d%d%d", &a, &b, &t);
if (a < ma)
ma = a;
if (b > mb)
mb = b;
for (j = a; j <= b; j++)
ans[j]++;
sum += t;
}
j = 0;
int max = -1,k,x=0;
while (sum != 0) {
for (i = ma; i <= mb; i++)
if (ans[i] > max) {
max = ans[i];
k = i;
}
ans[k] = -1;
sum -= max;
x++;
}
return x;
}
//飞机最优旅行费用问题:dijkstra应用
int d[n];
int S[n];
int src=0, dst=7;
int airtravel(graph g) {
int i, j, k,min;
S[src] = 0;
for (i = 0; i < n; i++)
d[i] = g.edge[src][i];
for (i = 0; i < n; i++) {
min = 999;
for (j = 0; j < n; j++)
if (g.edge[i][j] != 0 && g.edge[i][j] < min) {
min = g.edge[i][j];
k = j;
}
S[k] = 1;
for (j = 0; j < n; j++) {
if (g.edge[k][j] != 0 && S[j] == 0 && min + g.edge[k][j] < d[j])
d[j] = min + g.edge[k][j];
}
}
return d[dst];
}
int main() {
graph g;
struct edge edge[6];
int parent[6] = { 0 };
int rank[6];
for(int i=0;i<vernum;i++){
scanf_s("%d%d%d", &edge[i].a, &edge[i].b, edge->weight);
}
init(parent, rank);
kruskal(g, edge, parent, rank);
system("pause");
}
【复习】贪心算法
最新推荐文章于 2024-07-10 22:34:42 发布