补图


Time Limit: 1000 ms  Memory Limit: 65536 KiB
Problem Description

题目给出一个无向图,求该无向图关于完全图的相对补图,并求该补图的最大度和最小度。方便起见,用邻接矩阵表示该无向图。无向图的节点数不少于2并且不超过500.

Input

多组输入,每组输入第一行是无向图中节点的数量即邻接矩阵的行列数n。接下来n行n列为该图的邻接矩阵。

Output

每组数据,首先输出n行n列表示补图的邻接矩阵。接下来一行两个用空格分隔的整数,分别代表补图的最大度和最小度。

Sample Input
4
0 0 1 1
0 0 0 1
1 0 0 0
1 1 0 0
Sample Output
0 1 0 0
1 0 1 0
0 1 0 1
0 0 1 0
2 1
Hint
Source
一步踏尘千劫累

#include <stdio.h>  

#define MA 550  
  
  
int main()  
{  
    int n;  
    int G[500][500];  
    int i, j;  
    int max, min;  
    int deg;  
    while(~scanf("%d", &n))  
    {  
        max = 0;  
        min = MA;  
        for(i=0; i<n; i++)  
        {  
            deg = 0;                //初始化每个节点的度数  
            for(j=0; j<n; j++)  
            {  
                scanf("%d", &G[i][j]);  
                if(i != j)           //输入直接求补图该节点的边,减小时间复杂度  
                {  
                    if(G[i][j] == 1)  
                    {  
                        G[i][j] = 0;  
                    }  
                    else  
                    {  
                        G[i][j] = 1;  
                    }  
                }  
                if(G[i][j] == 1)  
                {  
                    deg++;          //计算度数  
                }  
            }  
            if(deg > max)  
            {  
                max = deg;  
            }  
            if(deg < min)  
            {  
                min = deg;  
            }  
        }  
  
  
        for(i=0; i<n; i++)  
        {  
            for(j=0; j<n-1; j++)  
            {  
                printf("%d ", G[i][j]);  
            }  
            printf("%d\n", G[i][j]);  
        }  
        printf("%d %d\n", max, min);  
    }  
    return 0;  
}  


### 关于补图的定义与性质 在论中,给定一个简单无向 \( G(V,E) \),其补图 \( \overline{G}(V,\overline{E}) \) 是指具有相同顶点集 \( V \),但边集 \( \overline{E} \) 中仅包含那些不在原 \( E \) 中的边。换句话说,如果两个节点 \( u,v \in V \) 在 \( G \) 中不相连,则它们在 \( \overline{G} \) 中必然相连。 以下是补图的一些重要特性: - 原补图的边集合互斥且覆盖所有可能的边组合[^1]。 - 如果原为完全,则其补图为空;反之亦然。 --- ### 补图算法的具体实现 #### 使用 NetworkX 实现补图计算 `NetworkX` 提供了一个内置函数 `complement(G)` 来快速生成任意补图。下面是一个完整的 Python 示例: ```python import networkx as nx import matplotlib.pyplot as plt # 创建原始 G G = nx.Graph() edges = [(1, 2), (2, 3), (3, 4)] G.add_edges_from(edges) # 计算补图 G_complement = nx.complement(G) # 可视化原补图 plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1) nx.draw(G, with_labels=True, node_color='lightblue', edge_color='gray') plt.title("Original Graph") plt.subplot(1, 2, 2) nx.draw(G_complement, with_labels=True, node_color='lightgreen', edge_color='red') plt.title("Complement Graph") plt.show() ``` 上述代码展示了如何创建一个简单的无向及其对应的补图,并通过可视化方式呈现两者的关系。 #### 手动实现补图算法 如果不借助第三方库,可以手动构建补图如下所示: ```python def generate_complement_graph(graph): """ 输入:graph - 字典形式表示的邻接表 {node: [neighbors]} 输出:complement_graph - 邻接表形式的补图 """ nodes = list(graph.keys()) complement_graph = {node: [] for node in nodes} n = len(nodes) all_pairs = set((nodes[i], nodes[j]) for i in range(n) for j in range(i + 1, n)) existing_edges = set() for u, neighbors in graph.items(): for v in neighbors: if u < v: existing_edges.add((u, v)) else: existing_edges.add((v, u)) missing_edges = all_pairs - existing_edges for u, v in missing_edges: complement_graph[u].append(v) complement_graph[v].append(u) return complement_graph # 测试用例 original_graph = { 1: [2], 2: [1, 3], 3: [2, 4], 4: [3] } complement_graph = generate_complement_graph(original_graph) print(complement_graph) ``` 此代码片段实现了从邻接表形式的输入生成其补图的功能[^3]。 --- ### 判断两是否为彼此的补图 为了验证两张是否互为补图,需满足以下条件: 1. 它们的顶点集完全一致; 2. 对于任一顶点对 \( (u,v) \),要么属于其中一个的边集,要么属于另一个的边集,二者必居其一。 可以通过以下伪代码描述该过程: ```plaintext function is_complement(G1, G2): if vertices(G1) != vertices(G2): return False edges_union = union(edges(G1), edges(G2)) possible_edges = {(i,j) | ∀ i ≠ j ∈ vertices(G1)} return edges_union == possible_edges and intersection(edges(G1), edges(G2)) == ∅ ``` 实际编码时可参考以下 Python 版本: ```python def are_complements(graph1, graph2): """判断两个是否互为补图""" # 检查顶点集一致性 if set(graph1.keys()) != set(graph2.keys()): return False # 构造全连接的所有可能边 nodes = list(graph1.keys()) all_possible_edges = set( tuple(sorted([nodes[i], nodes[j]])) for i in range(len(nodes)) for j in range(i + 1, len(nodes)) ) # 获取两个的实际边集 def get_edges(g): edges_set = set() for u, neighbors in g.items(): for v in neighbors: edges_set.add(tuple(sorted([u, v]))) return edges_set edges_g1 = get_edges(graph1) edges_g2 = get_edges(graph2) # 边集应互补且覆盖全部可能性 return edges_g1.union(edges_g2) == all_possible_edges and not (edges_g1.intersection(edges_g2)) ``` --- ### 性能优化考虑 对于大规模稀疏,直接枚举所有可能边可能导致性能瓶颈。因此,在实际应用中建议先估算所需存储空间以及时间复杂度后再决定是否采用暴力法或更高效的启发式策略。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值