贪心算法题解(最小生成树专题)

A. 最小生成树

Description

在一张图上有N个点,点与点之间的连接的花费都已经告诉你了,请你设计一下,如何解决这个“最小生成树”的问题。要求用prim方法求解。

Input

首先输入一个数字N(0〈=N〈=100)

​ 然后输入一个N*N的矩阵 其中第i行第j列的数字k表示从点i到点j需要的花费。

Output

一个数字,最少需要多少花费才能使得整张图任意两点都直接或者间接连通(也就是最小生成树的权)

Sample Input

5
0 41 67 34 0 
41 0 69 24 78 
67 69 0 58 62 
34 24 58 0 64 
0 78 62 64 0

0

2
0 1
1 0

Sample Output

116
0
1

Answer

#include <bits/stdc++.h>
using namespace std;
#define MAX 101
#define INF 999999999
struct Tedge {
	int nP1;
	int nP2;
	int nW;
};
int nCost[MAX][MAX];
bool bV1[MAX],bV2[MAX];
void vInput(int nA);
int nPrim(int nA);
Tedge tGetEdge(int nA);
void vInit();
int main() {
	int n,nAns;;
	while(1==scanf("%d",&n)) {
		vInit();
		vInput(n);
		if(n!=0) {
			nAns=nPrim(n);
		} else {
			nAns=0;
		}
		printf("%d\n",nAns);
	}
	return 0;
}
void vInit() {
	memset(bV1,false,sizeof(bV1));
	memset(bV2,true,sizeof(bV2));
}
void vInput(int nA) {
	int i,j;
	for(i=1; i<=nA; i++) {
		for(j=1; j<=nA; j++) {
			scanf("%d",&nCost[i][j]);
		}
	}
}
int nPrim(int nA) {
	int nRet,nC;
	Tedge tA;
	nRet=0;
	nC=1;
	bV1[1]=true;
	bV2[1]=false;
//	到最小生成树有nA个顶点为止 
	while(nC<nA) {
		tA=tGetEdge(nA);
		bV1[tA.nP2]=true;
		bV2[tA.nP2]=false;
		nRet+=tA.nW;
		nC++;
	}
	return nRet;
}
Tedge tGetEdge(int nA) {
	Tedge tRet;
	int i,j,nF,nT,nMinV;
	nF=1;
	nT=1;
//	nMinV表示权值最小的边 
	nMinV=INF;
	for(i=1; i<=nA; i++) {
//		如果顶点i在最小生成树中 
		if(bV1[i]) {
			for(j=1; j<=nA; j++) {
//				且顶点j不在最小生成树中 
				if(bV2[j]) {
					if(nMinV>nCost[i][j]) {
						nMinV=nCost[i][j];
						nF=i;
						nT=j;
					}
				}
			}
		}
	}
	tRet.nP1=nF;
	tRet.nP2=nT;
	tRet.nW=nMinV;
	return tRet;
}

B. 图的连通性问题-其他方法

Description

图论中有一个基本的问题,那就是一个无向图的连通性判别问题,今天我们就来讨论这个问题,我们知道,在计算机中一张图可以有两种表示方法,一是邻接矩阵二是邻接表,其中的邻接矩阵表示方法,我们已经在课堂上介绍最小生成树问题时讨论过,今天我们就来讨论用邻接表表示的图的连通性问题。要求不能用DFS、BFS、并查集三种方法求解。

Input

本问题有多组测试数据,每组测试数据有两部分,第一部分只有一行,是两个正整数,分别表示图的节点数N(节点编号从1到N,1<=N<=100)和图的边数E;第二部分共有E行,每行也是两个整数N1,N2(1<=N1,N2<=N),分别表示N1和N2之间有一条边。

Output

对于每一组测试数据,输出只有一行,如果是连通图,那么输出“Yes”,否则输出“No”。

Sample Input

6 10
1 2
1 3
1 4
1 5
1 6
2 3
2 4
3 4
3 5
3 6
4 3
1 2
1 3
2 3

Sample Output

Yes
No

Answer

#include <bits/stdc++.h>
using namespace std;
#define MAX 5001

bool bV[MAX];
bool bE[MAX][MAX];
void vInit();
void vInput(int nE);
void vConfirm(int nE);
void vOut(int nN);

int main() {
	int nNode,nEdge;
	while(cin>>nNode>>nEdge) {
		vInit();
		vInput(nEdge);
		vConfirm(nEdge);
		if(nNode<=0||nEdge<=0){
			cout<<"No"<<endl;
			continue;
		}
		vOut(nNode);
	}
	return 0;
}
void vInit() {
	memset(bV,false,sizeof(bV));
	memset(bE,false,sizeof(bE));
}
void vInput(int nE) {
	int i;
	int nF,nT,nD,nV;
	for(i=1; i<=nE; i++) {
		scanf("%d%d",&nF,&nT);
		bE[nF][nT]=true;
		if(nF==1) {
			bV[nF]=true;
			bV[nT]=true;
		} else {
			if(bV[nF]) {
				bV[nT]=true;
			} else if(bV[nT]) {
				bV[nF]=true;
			}
		}
	}
}
void vConfirm(int nE) {
	int i;
	int j;
	for(i=1; i<=nE; i++) {
		for(j=1; j<=nE; j++) {
			if(bE[i][j]) {
				if(bV[i]) {
					bV[j]=true;
				} else if(bV[j]) {
					bV[i]=true;
				}
			}
		}
	}
}
void vOut(int nN) {
	int i;
	bool bRet=true;
	for(i=1; i<=nN; i++) {
		if(!bV[i]) {
			bRet=false;
			break;
		}
	}
	if(bRet) {
		cout<<"Yes"<<endl;
	} else {
		cout<<"No"<<endl;
	}
}

C. 不同条件下的最小生成树

Description

课堂上我们学习了最小生成树的算法思想,也在实验课自己动手实现了这个算法,今天我们仍然要求来实现这个算法,只不过输入要求不一样,而且给定的图也不是所有顶点之间都有连接的边,有些顶点之间没有边,要求计算的最小费用也有点变化,请准确理解并求解.

Input

输入的第一行是测试数据的组数,对于每一组测试数据,有两部分,第一部分只有一行,分别有两个正整数nNode、nEdge(分别表示图的顶点数、边数,其中顶点编号为1到nNode,1<=nNode<=100);第二部分共有nEdge行,每行有四个正整数nFrom、nTo、nDist、nV(分别表示这一条边的起始顶点、终止顶点、边的长度、这条边上能够承载的速度,当然它们的单位已经换算成相应的标准单位了,你不用考虑单位换算的问题;其中1<=nFrom,nTo<=nNode)。输入数据保证能够有生成树,每条边在计算费用时假设是各自的匀速运动。

Output

你的任务是以每条边上能承载的速度前提下将所需时间作为边的费用,求出最小生成树的花费,输出只有一行,即所求的花费,输出时保留一位小数。

Sample Input

1
6 10
1 2 6 3
1 3 1 1
1 4 5 2
2 3 5 3
2 5 3 2
3 4 5 3
3 5 6 3
3 6 4 2
4 6 2 1
5 6 6 3

Sample Output

7.8

Answer

#include <bits/stdc++.h>
using namespace std;
#define MAX 101
#define INF 999999999.9
struct Tedge {
	int nP1;
	int nP2;
	double nW;
};
double nCost[MAX][MAX];
bool bV1[MAX],bV2[MAX];
void vInput(int nE);
double nPrim(int nA);
Tedge tGetEdge(int nA);
void vInit();
int main() {
	int k,i,nNode,nEdge;
	double nAns;
	scanf("%d",&k);
	for(i=1; i<=k; i++) {
		vInit();
		scanf("%d%d",&nNode,&nEdge);
		vInput(nEdge);
		if(nNode!=0) {
			nAns=nPrim(nNode);
		} else {
			nAns=0;
		}
		printf("%.1lf\n",nAns);
	}
	return 0;
}
void vInit() {
	int i,j;
	memset(bV1,false,sizeof(bV1));
	memset(bV2,true,sizeof(bV2));
	for(i=0; i<MAX; i++) {
		for(j=0; j<MAX; j++) {
			nCost[i][j]=INF;
		}
	}
}
void vInput(int nE) {
	int i;
	int nF,nT,nD,nV;
	for(i=1; i<=nE; i++) {
		scanf("%d%d%d%d",&nF,&nT,&nD,&nV);
		nCost[nF][nT]=1.0*nD/nV;
		nCost[nT][nF]=nCost[nF][nT];
	}
}
double nPrim(int nA) {
	int nC;
	double nRet;
	Tedge tA;
	nRet=0.0;
	nC=1;
	bV1[1]=true;
	bV2[1]=false;
	while(nC<nA) {
		tA=tGetEdge(nA);
		bV1[tA.nP2]=true;
		bV2[tA.nP2]=false;
		nRet+=tA.nW;
		nC++;
	}
	return nRet;
}
Tedge tGetEdge(int nA) {
	Tedge tRet;
	int i,j,nF,nT;
	double nMinV;
	nF=1;
	nT=1;
	nMinV=INF;
	for(i=1; i<=nA; i++) {
		if(bV1[i]) {
			for(j=1; j<=nA; j++) {
				if(bV2[j]) {
					if(nMinV>nCost[i][j]) {
						nMinV=nCost[i][j];
						nF=i;
						nT=j;
					}
				}
			}
		}
	}
	tRet.nP1=nF;
	tRet.nP2=nT;
	tRet.nW=nMinV;
	return tRet;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值