【复习】贪心算法

#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");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值