有向图 同构

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

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

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

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

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

这里有个特殊情况就是,当一个节点的出度和入度在这张图中唯一,那么在另一张图中也一定有唯一一个节点有相应的出度和入度,于是这个不用搜索就可以确定,可以预处理。如上第一个图的节点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 }
posted @ 2011-07-04 22:00  freewater  阅读(2465)  评论(0编辑  收藏  举报