实验9 图连通与最小生成树2022

题目描述

输入无向图顶点信息和边信息,创建图的邻接矩阵存储结构,计算图的连通分量个数。

输入

测试次数t

每组测试数据格式如下:

第一行:顶点数 顶点信息

第二行:边数

第三行开始,每行一条边信息

输出

每组测试数据输出,顶点信息和邻接矩阵信息

输出图的连通分量个数,具体输出格式见样例。

每组输出直接用空行分隔。

输入:

3
4 A B C D
2
A B
A C
6 V1 V2 V3 V4 V5 V6
5
V1 V2
V1 V3
V2 V4
V5 V6
V3 V5
8 1 2 3 4 5 6 7 8
5
1 2
1 3
5 6
5 7
4 8

输出:

A B C D
0 1 1 0
1 0 0 0
1 0 0 0
0 0 0 0
2

V1 V2 V3 V4 V5 V6
0 1 1 0 0 0
1 0 0 1 0 0
1 0 0 0 1 0
0 1 0 0 0 0
0 0 1 0 0 1
0 0 0 0 1 0
1

1 2 3 4 5 6 7 8
0 1 1 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 1 1 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
3

代码:

#include<iostream>
#include<queue>
using namespace std;
int count = 1;
string* s, s1, s2;
int** matrix, * mer;
int index(string s1,int sum) {
    for (int i = 0; i <sum; i++)
        if (s[i] == s1) return i;
}
int find(string s1,int sum) {
    int ind = index(s1, sum);
    while (ind != mer[ind]) {
        ind = mer[ind];
    }
    int a=index(s1,sum), b;
    while (a != ind) {
        b = mer[a];
        mer[a] = ind;
        a = b;
    }
    return ind;
}
void merge(string s1, string s2,int sum) {
    int f1 = find(s1,sum), f2 = find(s2,sum);
    if (f1 != f2)
        mer[f2] = f1;
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        int sum,relation;
        cin >> sum;
        mer = new int[sum];
        for (int i = 0; i < sum; i++)
            mer[i] = i;
        s = new string[sum];
        for (int i = 0; i < sum; i++)
            cin >> s[i];
        for (int i = 0; i < sum-1; i++)
            cout << s[i] << " ";
        cout << s[sum - 1] << endl;
        matrix = new int* [sum];
        for (int i = 0; i < sum; i++) matrix[i] = new int[sum];
        for (int i = 0; i < sum; i++)
            for (int j = 0; j < sum; j++)
                matrix[i][j] = 0;
        cin >> relation;
        for (int i = 0; i < relation; i++) {
            cin >> s1 >> s2;
            matrix[index(s1, sum)][index(s2, sum)] = 1;
            matrix[index(s2, sum)][index(s1, sum)] = 1;
            merge(s1, s2,sum);
        }
        for (int i = 0; i < sum; i++) {
            for (int j = 0; j < sum - 1; j++)
                cout << matrix[i][j] << " ";
            cout << matrix[i][sum - 1] << endl;
        }
        int count=0;
        for (int i = 0; i < sum; i++)
            if (mer[i] == i) count++;
        cout << count << endl << endl;
    }
}

B. 村村通工程(Kruskal算法)

题目描述

"村村通"是国家一个系统工程,其包涵有:公路、电力、生活和饮用水、电话网、有线电视网、互联网等等。

村村通公路工程,是国家为构建和谐社会,支持新农村建设的一项重大举措,是一项民心工程。又称“五年千亿元”工程

该工程是指中国力争在5年时间实现所有村庄通沥青路或水泥路,以打破农村经济发展的交通瓶颈,解决9亿农民的出行难题。

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

要求用Kruskal算法求解

输入

第1行:顶点数n

第2行:n个顶点编号

第3行:边数m

接着m行:m条边信息,格式为:顶点1 顶点2 权值

输出

第1行:输出最小生成树的权值之和

接着n-1行对应n-1条边信息

如果能找到最小生成树,按树的生长顺序输出, 边顶点按数组序号升序输出

如果输入数据不足以保证畅通,则直接输出−1,无需输出任何边信息

输入:

6
v1 v2 v3 v4 v5 v6 
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6

输出:

15
v1 v3 1
v4 v6 2
v2 v5 3
v3 v6 4
v2 v3 5

代码:

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#include<string>
using namespace std;
int pre[1000];//并查集数组,有多少个指向自己就有多少个连通分量(pre[i]=i)
//对应顶点编号下标
class Node
{
public:
    string x, y;//有连接的顶点
    int dis;//路径距离
};
bool compare(Node n1, Node n2) {//升
    return n1.dis < n2.dis;
}
int find(int x) {
    if (pre[x] == x)
        return x;
    pre[x] = find(pre[x]);
    return pre[x];
}
void  unite(int x, int y) {
    int f1 = find(x);
    int f2 = find(y);
    if (f1 != f2)
        pre[f2] = f1;
}
int main() {
    int num;
    cin >> num;
    vector<string> res;
    map<string, int> ma;
    for (int i = 0; i < num; i++) {
        string s;
        cin >> s;
        ma[s] = i;
        pre[i] = i;
    }
    int arcnum;
    cin >> arcnum;
    if (arcnum >= num - 1) {
      Node* node = new Node[arcnum];
      for (int i = 0; i < arcnum; i++) {
          cin >> node[i].x >> node[i].y >> node[i].dis;
          if (node[i].x > node[i].y)
              swap(node[i].x, node[i].y);
     }
      sort(node, node + arcnum, compare);
      int sum = 0;
      for (int i = 0; i < arcnum; i++) {
          int x = ma[node[i].x];
          int y = ma[node[i].y];
          if (find(x) != find(y)) {
              unite(x, y);
              sum += node[i].dis;
              string s = node[i].x + " " + node[i].y + " " + to_string(node[i].dis);
              res.push_back(s);
          }
      }
      int root = 0;
      for (int i = 0; i < num; i++)
          if (pre[i] == i)
              root++;
      if (root == 1) 
      {
          cout << sum << endl;
          for (int i = 0; i < res.size(); i++)
              cout << res[i] << endl;
      }
      else cout << -1 << endl;
    }
    else
        cout << -1 << endl;
}

C. 村村通工程(Prim算法)

题目描述

"村村通"是国家一个系统工程,其包涵有:公路、电力、生活和饮用水、电话网、有线电视网、互联网等等。

村村通公路工程,是国家为构建和谐社会,支持新农村建设的一项重大举措,是一项民心工程。又称“五年千亿元”工程

该工程是指中国力争在5年时间实现所有村庄通沥青路或水泥路,以打破农村经济发展的交通瓶颈,解决9亿农民的出行难题。

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

要求用Prim算法求解

输入

第1行:顶点数n

第2行:n个顶点编号

第3行:边数m

接着m行:m条边信息,格式为:顶点1 顶点2 权值

最后一行:Prim算法的起点v

输出

第1行:输出最小生成树的权值之和

接着n-1行对应n-1条边信息

按树的生长顺序输出

输入:

6
v1 v2 v3 v4 v5 v6 
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1

输出:

15
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3

代码:

#include <iostream>
using namespace std;
int Visit[300];
int Map[300][300];
class node
{
public:
 string from, to;
 int dis;
};
int check(string data[], string s, int n)
{
 for (int i = 0; i < n; i++)
  if (s == data[i])
   return i;
}
void setMap(int i, int j, int w)
{
 Map[i][j] = w;
 Map[j][i] = w;
}
void Prime(int start, int n, string data[])
{
 Visit[start] = 1;
 int Min = 1000;
 int sum = 0;
 int tempi;
 int tempj;
 int t = 0;
 node ans[1000];
 while (true)
 {
  Min = 1000;
  for (int j = 0; j < n; j++)
  {
   if (!Visit[j])
    continue;
   for (int i = 0; i < n; i++)
   {
    if (Map[i][j] != 0 && Map[i][j] < Min&&!Visit[i])
    {
     Min = Map[i][j];
     tempj = j;
     tempi = i;
    }
   }
  }
  Visit[tempi] = 1;
  ans[t].dis = Map[tempi][tempj];
  ans[t].from = data[tempj];
  ans[t].to = data[tempi];
  sum += Map[tempi][tempj];
  Map[tempi][tempj] = 0;
  Map[tempj][tempi] = 0;
  if (++t >= n - 1)
   break;
 }
 cout << sum << endl;
 for (int i = 0; i < n - 1;i++)
 {
  cout << ans[i].from << ' ' << ans[i].to << ' ' << ans[i].dis << endl;
 }
}
int main()
{
 int n;
 cin >> n;
 string data[n];
 for (int i = 0; i < n; i++)
  cin >> data[i];
 int k;
 cin >> k;
 node edge[k];
 node temp[k];
 for (int i = 0; i < k; i++)
 {
  cin >> edge[i].from >> edge[i].to >> edge[i].dis;
  setMap(check(data, edge[i].from, n), check(data, edge[i].to, n), edge[i].dis);
 }
 string start;
 cin >> start;
 Prime(check(data, start, n), n,data);
 return 0;
}

E. 汉密尔顿回路

题目描述

著名的“汉密尔顿(Hamilton)回路问题”是要找一个能遍历图中所有顶点的简单回路(即每个顶点只访问 1 次)。本题就要求你判断任一给定的回路是否汉密尔顿回路。

输入

首先第一行给出两个正整数:无向图中顶点数 N2<N≤200)和边数 M。随后 M 行,每行给出一条边的两个端点,格式为“顶点1 顶点2”,其中顶点从 1 到N 编号。再下一行给出一个正整数 K,是待检验的回路的条数。随后 K 行,每行给出一条待检回路,格式为:

n V1 V2 Vn

其中 n 是回路中的顶点数,Vi 是路径上的顶点编号。

输出

对每条待检回路,如果是汉密尔顿回路,就在一行中输出"YES",否则输出"NO"。

输入:

6 10
6 2
3 4
1 5
2 5
3 1
4 1
1 6
6 3
1 2
4 5
6
7 5 1 4 3 6 2 5
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 3 4 5 2 6
7 6 1 2 5 4 3 1

输出:

YES
NO
NO
NO
YES
NO

代码:

#include <iostream>
using namespace std;
int check(int a, int b, int Map1[], int Map2[], int M)
{
    for (int j = 0; j < M; j++)
    {
        if ((a == Map1[j] && b == Map2[j]) || (b == Map1[j] && a == Map2[j]))
        {
            return 1;
        }
    }
    return 0;
}
int main()
{
    int N, M;
    cin >> N >> M;
    int Map1[M];
    int Map2[M];
    for (int i = 0; i < M; i++)
        cin >> Map1[i] >> Map2[i];
    int K;
    cin >> K;
    while (K--)
    {
        int n;
        cin >> n;
        int arr[n];
        int Visit[n-1];
        for (int i = 0; i < n; i++)
        {
            cin >> arr[i];
            Visit[i] = 0;
        }
        if (n != N + 1 || arr[0] != arr[n - 1])
        {
            cout << "NO" << endl;
            continue;
        }
        int sign = 0;
        for (int i = 0; i < n - 1; i++)
        {
            if (Visit[arr[i]-1] || !check(arr[i], arr[i + 1], Map1, Map2, M))
            {
                cout << "NO" << endl;
                sign = 1;
                break;
            }
            Visit[arr[i] - 1] = 1;
        }
        Visit[arr[0]] = 1;
        if (sign)
            continue;
        for (int i = 0; i < n-1; i++)
            if (!Visit[i])
            {
                cout << "NO" << endl;
                sign = 1;
                break;
            }
        if (!sign)
            cout << "YES" << endl;
    }
}

F. 红色警报

题目描述

战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

输入

输入在第一行给出两个整数N(0 < N 500)和M( 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出

对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.

输入:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

输出:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.

代码:

#include <iostream>
using namespace std;
const int MaxLen = 20;
class Map
{
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;
    void dfs(int index);

public:
    void SetMatrix(int vnum);
    void Setundigraph(int i1, int i2);
    void Print();
    int Count();
    void lost(int i);
};
void Map::lost(int i)
{
    for (int j = 0; j < Vexnum; j++)
    {
        if (Matrix[j][i])
        {
            Matrix[i][j] = 0;
            Matrix[j][i] = 0;
        }
    }
}
void Map::dfs(int index)
{
    Visit[index] = 1;
    for (int i = 0; i < Vexnum; i++)
    {
        if (Matrix[index][i] && !Visit[i])
        {
            dfs(i);
        }
    }
}
int Map::Count()
{
    int temp = 0;
    for (int i = 0; i < Vexnum; i++)
        Visit[i] = 0;
    for (int i = 0; i < Vexnum; i++)
    {
        if (!Visit[i])
        {
            temp++;
            dfs(i);
        }
    }
    return temp;
}
void Map::SetMatrix(int vnum)
{
    int i, j;
    Vexnum = vnum;
    for (i = 0; i < MaxLen; i++)
        for (j = 0; j < MaxLen; j++)
            Matrix[i][j] = 0;
}
void Map::Setundigraph(int i1, int i2)
{
    Matrix[i1][i2] = 1;
    Matrix[i2][i1] = 1;
}
void Map::Print()
{
    for (int i = 0; i < Vexnum; i++)
        for (int j = 0; j < Vexnum; j++)
        {
            cout << Matrix[i][j];
            if (j != Vexnum - 1)
                cout << ' ';
            else
                cout << endl;
        }
    cout << Count() << endl
        << endl;
}
int main()
{
    int n, k;
    cin >> n;
    cin >> k;
    Map m;
    m.SetMatrix(n);
    int a, b;
    while (k--)
    {
        cin >> a >> b;
        m.Setundigraph(a, b);
    }
    cin >> k;
    int temp = m.Count();
    int t = k;
    while (k--)
    {
        int a;
        cin >> a;
        m.lost(a);
        if (m.Count() - 1 > temp)
        {
            temp = m.Count() - 1;
            cout << "Red Alert: City " << a << " is lost!" << endl;
        }
        else
            cout << "City " << a << " is lost." << endl;
    }
    if (t == n)
        cout << "Game Over." << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值