Skip to content

Commit cfe440c

Browse files
committedDec 30, 2019
1094
1 parent 8b119c8 commit cfe440c

File tree

2 files changed

+267
-0
lines changed

2 files changed

+267
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
## [[POJ](http://poj.org/)] [[INDEX](https://github.com/lyy289065406/POJ-Solving-Reports)] [1094] [[Sorting It All Out](http://poj.org/problem?id=1094)]
2+
3+
> [Time: 1000MS] [Memory: 10000K] [难度: 初级] [分类: 拓扑排序]
4+
5+
------
6+
7+
## 问题描述
8+
9+
无。
10+
11+
12+
## 解题思路
13+
14+
**提示:** 拓扑排序
15+
16+
这道题有隐含这一信息,每输入一对关系,如果判定有结果,则可以忽略后面输入数据,即使后面输入数据能改变结果,也不用管。所以应该每输入一个关系就去更新当前的图,然后进行一趟拓扑排序。一旦产生结果,再对后面的数据处理下,就可以输出结果。
17+
18+
------
19+
20+
下面罗列所有可能的情况(类似于**状态机**):
21+
22+
23+
一、当输入的字母全部都在前n个大写字母范围内时:
24+
25+
(1)最终的图 可以排序:
26+
  在输入结束前如果能得到最终的图(就是用这n个字母作为顶点,一个都不能少);
27+
  而且最终得到的图 无环;
28+
  只有唯一一个 无前驱(即入度为0)的结点,但允许其子图有多个无前驱的结点。
29+
  在这步输出排序后,不再对后续输入进行操作
30+
31+
(2)输出矛盾
32+
  在输入结束前如果最终图的子图有环
33+
  在这步输出矛盾后,不再对后续输入进行操作
34+
35+
(3)输出无法确认排序
36+
  这种情况必须全部关系输入后才能确定,其中又有2种可能
37+
    ① 最终图的字母一个不缺,但是有多个 无前驱结点
38+
    ② 输入结束了,但最终的图仍然字母不全,与 无前驱结点 的多少无关
39+
40+
二、当输入的字母含有 非前n个大写字母 的字母时(超出界限):
41+
42+
(1)输出矛盾
43+
  输入过程中检查输入的字母(结点),若 前n个大写字母 全部出现,则在最后一个大写字母出现的那一步 输出矛盾
44+
45+
(2)输出无法确认排序
46+
  最后一步输入后,前n个大写字母 仍然未全部出现,则输出 无法确认排序
47+
48+
------
49+
50+
**注意:**
51+
52+
在使用“无前驱结点”算法时必须要注意,在“矛盾优先”的规律下,必须考虑一种特殊情况,就是多个无前驱结点与环共存时的情况,即输入过程中子图都是有 多个无前驱结点,最后一步输入后出现了环,根据算法的特征,很容易输出“不能确认排序”,这是错的,必须适当修改算法,输出“矛盾”。
53+
54+
例如:
55+
56+
```
57+
6 6
58+
A<F
59+
B<D
60+
C<E
61+
F<D
62+
D<E
63+
E<F
64+
```
65+
66+
输出矛盾
67+
68+
69+
## AC 源码
70+
71+
72+
```c
73+
//Memory Time
74+
//276K 0MS
75+
76+
#include<iostream>
77+
using namespace std;
78+
79+
int n,m; //n结点下限,m关系对
80+
char top_out[26]; //排序输出列表
81+
int po=0; //输出列表的指针
82+
83+
typedef class degree
84+
{
85+
public:
86+
int in; //入度
87+
char to[26]; //记录指向的所有顶点,以便删除出度的操作
88+
int pt; //数组to的指针
89+
};
90+
91+
int top_sort(degree alph[],bool mark[],int num)
92+
{
93+
/*假设图G的当前子图为F*/
94+
95+
memset(top_out,'\0',sizeof(top_out));
96+
po=0;
97+
98+
int del_n=0;
99+
int zero=0; //记录图F中入度为0的结点个数
100+
for(int i='A';i<'A'+n;i++)
101+
if(mark[i] && !alph[i].in)
102+
zero++;
103+
104+
bool flag=false;
105+
while(zero>0)
106+
{
107+
if(zero>1) //图F的无前驱结点的个数不唯一,排序无法确定
108+
flag=true; //考虑到"矛盾"的优先性,避免在多个0入度结点情况下,最后一步输入刚好出现环(此时为矛盾)
109+
//所以这里先不返回值,而是先标记,执行拓扑,根据情况决定返回值
110+
111+
for(int k='A';k<='A'+n;k++) //寻找图F的唯一的前驱结点
112+
if(mark[k] && !alph[k].in)
113+
{
114+
mark[k]=false; //删除图F的唯一无前驱结点k
115+
del_n++; //记录删除的结点数
116+
top_out[po++]=k; //k记录到排序输出列表
117+
for(int i=0;i<alph[k].pt;i++) //删除结点k的所有出度边
118+
alph[ alph[k].to[i] ].in--;
119+
break;
120+
}
121+
122+
zero=0;
123+
for(int j='A';j<='A'+n;j++)
124+
if(mark[j] && !alph[j].in)
125+
zero++;
126+
}
127+
128+
if(flag && del_n==num)
129+
return 3;
130+
if(del_n<num) //说明图F存在有向环,矛盾,与0入度结点的多少无关。因为矛盾优先
131+
return 2;
132+
if(!flag && del_n==num && del_n<n) //图F能排序,但不能确定图G是否能排序,还需继续输入观察
133+
return 3;
134+
if(!flag && del_n==n) //图G能排序
135+
return 1;
136+
}
137+
138+
int main(void)
139+
{
140+
int num; //标记前n个字母出现个数,用于最终检查是否前n个字母均已被读入
141+
//*_t[]是用于备份的额外数组
142+
bool mark['Z'+1],mark_t['Z'+1]; //标记当前图G所使用的字母(结点)
143+
degree alph['Z'+1],alph_t['Z'+1];
144+
145+
while(true)
146+
{
147+
/*Input*/
148+
149+
cin>>n>>m;
150+
151+
if(!n||!m)
152+
break;
153+
154+
/*Initial*/
155+
156+
memset(mark,false,sizeof(mark));
157+
memset(mark_t,false,sizeof(mark_t));
158+
num=0;
159+
160+
for(int k='A';k<'A'+n;k++)
161+
{
162+
alph[k].in=alph_t[k].in=0;
163+
alph[k].pt=alph_t[k].pt=0;
164+
memset(alph[k].to,'\0',sizeof(alph[k].to));
165+
memset(alph_t[k].to,'\0',sizeof(alph_t[k].to));
166+
}
167+
168+
/*Structure Maps*/
169+
170+
char x,symbol,y; //临时变量
171+
bool flag=false;
172+
bool sign=false;
173+
int value; //记录拓扑返回的值
174+
int step; //记录当前情况发生的步骤
175+
for(int pair=1;pair<=m;pair++)
176+
{
177+
cin>>x>>symbol>>y;
178+
179+
if(x>='A'+n || y>='A'+n) //当输入的结点不在前n个字母范围内时
180+
sign=true; //不再进行拓扑,单纯检查后续输入是否把前n个字母都输入了
181+
//为了区分非前n个字母的字母的输入时间,是在确认了排序或矛盾之前还是之后
182+
//在确认 排序或矛盾之前:flag=false,sign=true
183+
//在确认 排序或矛盾之后:flag=true,sign=true
184+
185+
if(!mark[x] && x<'A'+n)
186+
num++;
187+
if(!mark[y] && y<'A'+n)
188+
num++;
189+
190+
if(!flag && !sign)
191+
{
192+
value=0;
193+
194+
mark[x]=mark[y]=true; //顶点标记
195+
mark_t[x]=mark_t[y]=true;
196+
197+
alph[y].in++; //入度标记
198+
alph_t[y].in++;
199+
200+
alph[x].to[ alph[x].pt++ ]=y; //指向标记 & 指针移动
201+
alph_t[x].to[ alph_t[x].pt++ ]=y;
202+
203+
/*Top-Sort & Sign*/
204+
205+
value=top_sort(alph_t,mark_t,num); //每次输入后图都被更新,要重新拓扑
206+
if(value==1) //排序确认
207+
{
208+
step=pair; //记录确认排序的位置
209+
flag=true; //不再对后续输入处理
210+
}
211+
else if(value==2) //矛盾
212+
{
213+
step=pair; //记录矛盾发生的位置
214+
flag=true; //不再对后续输入处理
215+
}
216+
else if(value==3 && pair<m) //排序(暂时)无法确认,需继续处理后续输入
217+
for(int k='A';k<'A'+n;k++) //数据还原
218+
{
219+
mark_t[k]=mark[k];
220+
alph_t[k].in=alph[k].in;
221+
}
222+
223+
if(pair==m && value==0)
224+
value=3;
225+
}
226+
227+
if(sign && !flag && num==n) //在确认 排序或矛盾之前,当存在有非前n个字母的结点时的"矛盾"
228+
{
229+
step=pair;
230+
value=2;
231+
}
232+
else if(sign && !flag && pair==m && num<n) //在确认 排序或矛盾之前,当存在有非前n个字母的结点时的"无法确认排序"
233+
value=3;
234+
}
235+
236+
if(value==1)
237+
{
238+
cout<<"Sorted sequence determined after "<<step<<" relations: ";
239+
for(int i=0;i<po;i++)
240+
cout<<top_out[i];
241+
cout<<'.'<<endl;
242+
}
243+
else if(value==2)
244+
cout<<"Inconsistency found after "<<step<<" relations."<<endl;
245+
else if(value==3)
246+
cout<<"Sorted sequence cannot be determined."<<endl;
247+
}
248+
return 0;
249+
}
250+
```
251+
252+
------
253+
254+
## 版权声明
255+
256+
 [![Copyright (C) EXP,2016](https://img.shields.io/badge/Copyright%20(C)-EXP%202016-blue.svg)](http://exp-blog.com) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
257+
258+
259+
- Site: [http://exp-blog.com](http://exp-blog.com)
260+
- Mail: <a href="mailto:289065406@qq.com?subject=[EXP's Github]%20Your%20Question%20(请写下您的疑问)&amp;body=What%20can%20I%20help%20you?%20(需要我提供什么帮助吗?)">289065406@qq.com</a>
261+
262+
263+
------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (C)
2+
# Author: EXP
3+
# Site : http://exp-blog.com
4+
# Mail : 272629724@qq.com

0 commit comments

Comments
 (0)