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;
}