#define MaxWeight 1000
struct Node{//边信息
int v1;//顶点1下标
int v2;//顶点2下标
int weight;
};
class Map{
int len;//顶点数
string *name;//顶点数组
int **P;//邻接矩阵
int *v;//访问数组
Node *node;//存放边信息
public:
//图的创建函数...
void Prim(string start){
int p1, p2, min;
for(int i=0; i<len; i++){//初始化访问数组
v[i] = 0;
}
p1 = findPoint(start);//起始点下标
v[p1] = 1;
for(int i=0; i<len-1; i++){//len个顶点进行len-1次
min = MaxWeight;
for(int j=0; j<len; j++){
for(int k=0; k<len; k++){
if(v[j] == 1 && v[k] == 0 && p[j][k] < min){
p1 = j;
p2 = k;
min = p[j][k];
}
}
}
v[p2] = 1;
//将选出的边加入边集
node[i].v1 = p1;
node[i].v2 = p1;
node[i].weight = min;
}
}
int findPoint(string x){
int i;
for(i=0; i<len; i++){
if(name[i] == x){
break;
}
}
return i;
}
};
说明:(1) 在本程序中,邻接矩阵里权值为0的点也会被选中,如果想用0来表示点之间不连接需要做修改;(2) 这里的边集不是必需的,要看题目要求。如果题目不需要保留最小生成树的边信息,只要计算中权重值,直接用一个变量在循环中加总即可。
void Prim(string start){
int p1, p2, min;
//temp存放未选中点到已选中点的最小交叉边及其权值
Node *temp = new Node[len];
p1 = findPoint(start);
for(int i=0; i<len; i++){//初始化起始点p1到其余各结点的权值
temp[i].v1 = p1;
temp[i].weight = p[p1][i];
}
temp[p1].weight = 0;//权值设为0标志已访问
for(int i=0; i<len-1; i++){
min = MaxWeight;
for(int j=0; j<len; j++){
if(temp[j].weight!=0 && temp[j].weight<min){//在temp中找出权值最小的边
min = temp[j].weight;
p2 = j;
}
}
//将边加入边集
node[i].v1 = temp[p2].v1;
node[i].v2 = p2;
node[i].weight = min;
for(int j=0; j<len; j++){//检查新选中的p2是否使得剩余顶点的最小交叉边权值变小
if(temp[j].weight!=0 && temp[j].weight>p[p2][j]){
temp[j].weight = p[p2][j];
temp[j].v1 = p2;
}
}
temp[p2].weight = 0;//标志已访问
}
delete[] temp;
}
//这里提供一种对边排序的方法
bool cmp(const Node& n1, const Node& n2){
return n1.weight<n2.weight;
}
void SortNode(){//对边进行排序
int n=0;
for(int i=0; i<len; i++){
for(int j=i+1; j<len; j++){//无向图是对称矩阵,存一半的边即可,这里存的是上三角,不包括对角线
node[n].v1 = i;
node[n].v2 = j;
node[n].weight = p[i][j];
n++;
}
}
sort(node, node+n, cmp);
}
void Kruskal(){//边集事先排好序
int p1, p2, q1, q2;
int k = 0, count = 0;
for(int i=0; i<len; i++){//刚开始每个结点都是不同的连通分量
v[i] = i;
}
while(count<len-1){
p1 = node[k].v1;
p2 = node[k].v2;
if(v[p1] != v[p2]){
count++;//记录选出的边数
q1 = v[p1];
q2 = v[p2];
for(int i=0; i<len; i++){//将所有q1值换成q2,属于同一个连通分量
if(v[i] == q1) v[i] = q2;
}
}
k++;
}
}
题目描述
有N个村庄,编号从1到N,你应该建造一些道路,使每个村庄都可以相互连接。
两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C使得在A和C之间有一条道路,并且C和B相连。
现在一些村庄之间已经有一些道路,你的任务就是修建一些道路,使所有村庄都连通起来,并且所有道路的长度总和是最小的。
输入
测试数据有多组
第一行是整数N(3 <= N <= 100),代表村庄的数量。 然后是N行,其中第i行包含N个整数,这些N个整数中的第j个是村庄i和村庄j之间的距离(距离是[1,1000]内的整数)。
然后是整数Q(0 <= Q <= N *(N + 1)/ 2),接下来是Q行,每行包含两个整数a和b(1 <= a 输出
对于每组测试数据
输出一个整数,表示要构建的道路的长度总和最小值
样例输入
3
0 990 692
990 0 179
692 179 0
1
1 2
样例输出
179
分析:本题采用Prim算法较简单。主要在于如何处理已建成的道路:在邻接矩阵中将权值设为0即可。
#include
#include
using namespace std;
#define MaxWeight 1000
class Map{
int VertexNum;
int **matrix;
int *visited;
public:
Map(int t){
VertexNum = t;
matrix = new int*[VertexNum];
for(int i=0; i<VertexNum; i++){
matrix[i] = new int[VertexNum];
for(int j=0; j<VertexNum; j++){
cin >> matrix[i][j];
}
}
}
void set(int i, int j){//注意是无向图
matrix[i][j] = 0;
matrix[j][i] = 0;
}
void Prim(){
int sum = 0, min;
int pos;
visited = new int[VertexNum]();
visited[0] = 1;//设置起点
for(int i=0; i<VertexNum-1; i++){
min = MaxWeight;
for(int j=0; j<VertexNum; j++){
for(int k=0; k<VertexNum; k++){
if(visited[j] == 1 && visited[k] == 0 && matrix[j][k] < min){
pos = k;
min = matrix[j][k];
}
}
}
visited[pos] = 1;
sum += min;
}
cout<<sum<<endl;
}
~Map(){
if(visited){
delete[] visited;
}
for(int i=0; i<VertexNum; i++){
delete[] matrix[i];
}
delete[] matrix;
}
};
int main(){
int t;
while(cin >> t){
Map m(t);
int n;
cin >> n;
while(n--){
int a, b;
cin >> a >> b;
m.set(a-1, b-1);
}
m.Prim();
}
return 0;
}
//思路:道路建成的村庄将邻接矩阵中的值设为0
//使用Prim算法的简单版本,每次找到符合要求的边将权值加起来即可
题目描述
给定一个图的邻接矩阵,请判断该图是否是连通图。连通图:任意两个顶点之间都有路径。
–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
输入
第1行输入一个整数k,表示有k个测试数据
第2行输入一个整数n,表示有n个结点
从第3行起到第n+2行输入一个邻接矩阵,其中Matrix[i,j]=1表示第i,j个结点之间有边,否则不存在边。
接下来是第2到第k个测试数据的结点数和邻接矩阵
输出
输出Yes or No表示图是否是强连通图
样例输入
2
4
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
7
0 1 0 0 0 0 0
0 0 1 1 0 0 0
1 0 0 0 0 0 0
1 0 1 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 0 0 1 0 1 0
样例输出
Yes
No
分析:强连通图需要图中每个顶点都能到达所有顶点。这里用DFS,再计数即可。
#include
using namespace std;
class Map{
int VertexNum;
int **matrix;
int *visited;
void DFS(int v, int& count){
visited[v] = 1;
count++;
for (int j = 0; j < VertexNum; j++){
if(matrix[v][j] && !visited[j]){
DFS(j, count);
}
}
}
public:
void CreateMap();
void DFSTraverse();
};
void Map::CreateMap(){
cin >> VertexNum;
matrix = new int *[VertexNum];
for (int i = 0; i < VertexNum; i++){
matrix[i] = new int[VertexNum];
for (int j = 0; j < VertexNum; j++){
cin >> matrix[i][j];
}
}
}
void Map::DFSTraverse(){
visited = new int[VertexNum];
int sum = 0;
for (int i = 0; i < VertexNum; i++){
int count = 0;
for (int j = 0; j < VertexNum; j++){
visited[j] = 0;
}
DFS(i, count);
if(count == VertexNum){
sum++;
}
}
if(sum == VertexNum){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}
int main(){
int k;
cin >> k;
while(k--){
Map m;
m.CreateMap();
m.DFSTraverse();
}
return 0;
}
题目描述
给定有向图的邻接矩阵A,其元素定义为:若存在顶点i到顶点j的有向边则A[i,j]=1,若没有有向边则A[i,j]= 0。试求A的可达闭包矩阵A*,其元素定义为:若存在顶点i到顶点j的有向路径则A*[i,j]=1,若没有有向路径则A*[i,j]= 0。
输入
第1行顶点个数n
第2行开始的n行有向图的邻接矩阵,元素之间由空格分开
输出
有向图的可达闭包矩阵A*,元素之间由空格分开
样例输入
4
0 1 0 1
0 0 1 0
0 0 0 0
0 0 0 0
样例输出
0 1 1 1
0 0 1 0
0 0 0 0
0 0 0 0
#include
#include
using namespace std;
#define MaxWeight 1000
class Map{
int VertexNum;//顶点数
int **matrix;
int *visited;
void DFS(int v, int &index){
visited[v] = 1;
matrix[index][v] = 1;
for(int i=0; i<VertexNum; i++){
if(!visited[i] && matrix[v][i]){
DFS(i, index);
}
}
}
public:
Map(){
cin >> VertexNum;
matrix = new int*[VertexNum];
for(int i=0; i<VertexNum; i++){
matrix[i] = new int[VertexNum];
for(int j=0; j<VertexNum; j++){
cin >> matrix[i][j];
}
}
}
~Map(){
for(int i=0; i<VertexNum; i++){
delete[] matrix[i];
}
delete[] matrix;
}
void DFSTraverse(){
int flag;
visited = new int[VertexNum];
for(int i=0; i<VertexNum; i++){
//初始化访问数组
for(int j=0; j<VertexNum; j++){
visited[j] = 0;
}
DFS(i, i);
//检查顶点能否到达自己
flag = 0;
for(int j=0; j<VertexNum; j++){
if(i != j && matrix[i][j] && matrix[j][i]){
flag = 1;
break;
}
}
if(!flag){
matrix[i][i] = 0;
}
}
}
void getClosure(){
DFSTraverse();
for(int i=0; i<VertexNum; i++){
for(int j=0; j<VertexNum-1; j++){
cout << matrix[i][j] << ' ';
}
cout << matrix[i][VertexNum-1] << endl;
}
}
};
int main(){
Map m;
m.getClosure();
return 0;
}
//思路:使用DFS,途经的点在矩阵上标记为1
//顶点能否到达自己在于中途其他顶点能否到达该顶点,DFS后判断即可