有向图 同构

转载自:http://fghtech.blogbus.com/logs/56854632.html

http://162.105.81.212/JudgeOnline/problem?id=2040  

题意给定两个有向图,找出其同构的对应点,并输出其对应的序列。。。

416623112642540564.jpg

这题是给你两种语言的几个短语,让你翻译,求出各个单词的对应关系。

这里可以把单词抽象成点,把短语抽象成线,然后就是一个有向图了。于是问题就转化成了求两个同构图中各点的对应关系。由于题目规模比较小,所以可以用深度优先搜索。

这里有个特殊情况就是,当一个节点的出度和入度在这张图中唯一,那么在另一张图中也一定有唯一一个节点有相应的出度和入度,于是这个不用搜索就可以确定,可以预处理。如上第一个图的节点3和第二个图的节点0的出度和入度是对应的。

搜索条件是:对于第一张图pos这个节点,而且pos到k有一条边,k这个点在图中已经找到了匹配点,但是在第二张图中点i与该匹配点没有边相连,则pos的对应点一定不会是i

 
   
1 #pragma warning (disable : 4786)
2 #include < iostream >
3 #include < map >
4 #include < string >
5   using namespace std;
6   struct Node
7 {
8 string str;
9 int match; // 正数代表匹配节点编号,-1代表还没匹配
10 int outDegree, inDegree;
11 };
12 bool line1[ 25 ][ 25 ]; // 如果w[i] w[k]是一个短语,则line1[i][k] = true,代表一条从i指向k的边
13 bool line2[ 25 ][ 25 ];
14 Node node1[ 25 ], node2[ 25 ];
15 int n, n1, n2;
16 map < string , int > sim1, sim2; // 字符串到其下标的映射
17 void Init() // 读入,将字符串下标化,并建立好图
18 {
19 int i;
20 string str1, str2;
21 memset(line1, false , sizeof (line1));
22 memset(line2, false , sizeof (line2));
23 n1 = n2 = 0 ;
24 sim1.clear();
25 sim2.clear();
26 for (i = 0 ; i < 25 ; i ++ )
27 {
28 node1[i].outDegree = node1[i].inDegree = node2[i].outDegree = node2[i].inDegree = 0 ;
29 node1[i].match = node2[i].match = - 1 ;
30 }
31 for (i = 0 ; i < n; i ++ )
32 {
33 cin >> str1 >> str2;
34 if (sim1.find(str1) == sim1.end())
35 {
36 sim1[str1] = n1;
37 node1[n1 ++ ].str = str1;
38 }
39 if (sim1.find(str2) == sim1.end())
40 {
41 sim1[str2] = n1;
42 node1[n1 ++ ].str = str2;
43 }
44 line1[sim1[str1]][sim1[str2]] = true ;
45 node1[sim1[str1]].outDegree ++ ;
46 node1[sim1[str2]].inDegree ++ ;
47 }
48 for (i = 0 ; i < n; i ++ )
49 {
50 cin >> str1 >> str2;
51 if (sim2.find(str1) == sim2.end())
52 {
53 sim2[str1] = n2;
54 node2[n2 ++ ].str = str1;
55 }
56 if (sim2.find(str2) == sim2.end())
57 {
58 sim2[str2] = n2;
59 node2[n2 ++ ].str = str2;
60 }
61 line2[sim2[str1]][sim2[str2]] = true ;
62 node2[sim2[str1]].outDegree ++ ;
63 node2[sim2[str2]].inDegree ++ ;
64 }
65 }
66 void InitCompute() // 先根据特殊情况确定部分对应关系。
67 {
68 int i, k, samecnt;
69 for (i = 0 ; i < n1; i ++ )
70 {
71 samecnt = 0 ;
72 for (k = 0 ; k < n2; k ++ )
73 {
74 if (node2[k].outDegree == node1[i].outDegree && node2[k].inDegree == node1[i].inDegree)
75 {
76 samecnt ++ ;
77 node1[i].match = k;
78 }
79 }
80 if (samecnt > 1 )
81 node1[i].match = - 1 ;
82 else
83 node2[node1[i].match].match = i;
84 }
85 }
86 bool DFS( int pos) // 对第一张图深度优先搜索
87 {
88 if (pos < 0 ) // 搜索到解了
89 return true ;
90 else if (node1[pos].match != - 1 ) // 这个节点已经匹配
91 return DFS(pos - 1 );
92 else
93 {
94 int i, k, l;
95 for (i = 0 ; i < n2; i ++ )
96 {
97 if (node2[i].match == - 1 && node2[i].outDegree == node1[pos].outDegree && node2[i].inDegree == node1[pos].inDegree)
98 {
99 for (k = 0 ; k < n1; k ++ )
100 {
101 // 对于第一张图pos这个节点,而且pos到k有一条边,k这个点在图2中已经找到了匹配点,但是在第二张图中点i与该
102 // 匹配点没有边相连,则pos的对应点一定不会是i
103 if (k != pos && line1[pos][k] && node1[k].match != - 1 && ! line2[i][node1[k].match])
104 break ;
105 }
106 for (l = 0 ; l < n1; l ++ )
107 {
108 if (l != pos && line1[l][pos] && node1[l].match != - 1 && ! line2[node1[l].match][i])
109 break ;
110 }
111 if (k == n1 && l == n1) // 检查到没有冲突就匹配,继续搜
112 {
113 node1[pos].match = i;
114 node2[i].match = pos;
115 if (DFS(pos - 1 ))
116 return true ;
117 // 搜不到解就回溯
118 node1[pos].match = node2[i].match = - 1 ;
119 }
120 }
121 }
122 return false ;
123 }
124 }
125 void Print()
126 {
127 map < string , int > ::iterator iter, end = sim1.end();
128 for (iter = sim1.begin(); iter != end; iter ++ )
129 {
130 cout << iter -> first << ' / ' << node2[node1[iter -> second].match].str << endl;
131 }
132 }
133 int main()
134 {
135 // freopen("data.txt", "r", stdin);
136 for (scanf( " %d " , & n); ; )
137 {
138 Init();
139 InitCompute();
140 DFS(n1 - 1 );
141 Print();
142 scanf( " %d " , & n);
143 if (n == 0 )
144 break ;
145 else
146 printf( " \n " );
147 }
148 return 0 ;
149 }

转载于:https://www.cnblogs.com/freewater/archive/2011/07/04/2097784.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 C++ 程序,可用于判断两个有向图的邻接矩阵是否同构: ```c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAXN = 100; int n, m; // n 表示图中的节点数,m 表示图中的边数 int a[MAXN][MAXN]; // 存储第一个图的邻接矩阵 int b[MAXN][MAXN]; // 存储第二个图的邻接矩阵 bool vis[MAXN]; // 标记数组,用于深度优先搜索 // 判断两个邻接矩阵是否同构 bool isomorphic() { vector<int> va, vb; // 存储节点出度和入度的数组 int da[MAXN], db[MAXN], ina[MAXN], inb[MAXN], outa[MAXN], outb[MAXN]; // 存储节点出度和入度的数组 memset(da, 0, sizeof(da)); memset(db, 0, sizeof(db)); memset(ina, 0, sizeof(ina)); memset(inb, 0, sizeof(inb)); memset(outa, 0, sizeof(outa)); memset(outb, 0, sizeof(outb)); for (int i = 0; i < n; i++) { int d = 0; for (int j = 0; j < n; j++) { if (a[i][j]) { d++; outa[i]++; ina[j]++; } } da[d]++; va.push_back(d); } for (int i = 0; i < n; i++) { int d = 0; for (int j = 0; j < n; j++) { if (b[i][j]) { d++; outb[i]++; inb[j]++; } } db[d]++; vb.push_back(d); } sort(va.begin(), va.end()); sort(vb.begin(), vb.end()); for (int i = 0; i < n; i++) { if (da[i] != db[i]) return false; } for (int i = 0; i < n; i++) { if (va[i] != vb[i]) return false; } memset(vis, false, sizeof(vis)); for (int i = 0; i < n; i++) { if (!vis[i]) { vector<int> v1, v2; for (int j = 0; j < n; j++) { if (a[i][j]) v1.push_back(j); if (b[i][j]) v2.push_back(j); } sort(v1.begin(), v1.end()); sort(v2.begin(), v2.end()); if (v1 != v2) return false; for (int j = 0; j < v1.size(); j++) { vis[v1[j]] = true; } } } memset(vis, false, sizeof(vis)); for (int i = 0; i < n; i++) { if (ina[i] != inb[i] || outa[i] != outb[i]) return false; } return true; } int main() { cin >> n >> m; for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; u--, v--; a[u][v] = 1; } for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; u--, v--; b[u][v] = 1; } if (isomorphic()) { cout << "两个图同构" << endl; } else { cout << "两个图不同构" << endl; } return 0; } ``` 程序的基本思路和之前的程序类似,不同的是需要分别计算每个节点的入度和出度,并且在比较两个邻接矩阵中每个节点的邻居时,需要分别考虑其出度和入度的邻居。如果两个邻接矩阵同构,则它们具有相同的节点出度和入度序列,并且每个节点的出度和入度的邻居集合也相同。 下面是一个示例输入输出: 输入: ``` 3 0 1 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 0 ``` 输出: ``` 两个图同构 ``` 解释:输入的是两个 $3$ 阶有向图的邻接矩阵,分别是: ``` 0 1 1 1 0 1 1 1 0 ``` ``` 0 1 1 1 0 1 1 1 0 ``` 可以看出这两个图是同构的,因此输出 `两个图同构`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值