题目传送门
A题:
这道题实在写不出来了,只好参考了http://blog.csdn.net/sr_19930829/article/details/37883895 的代码;
需要注意这个题的顺序是:
1.判断有没有环,有环直接输出不确定;
2.如果没有环,那么就看会不会有多种情况,如果有多种情况就再读下一行;如果全部行读完还是有多种情况,就是确定不了;
3.如果最后没有环,也不存在多种情况(即每次取出来入度为零的点只有一个),那么才是答案;
4.有答案就先出答案,不管后面的会不会矛盾什么的;
5.如果在没有读完所有输入就能出答案,一定要把剩下的行都读完。
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
using namespace std;
int indegree[30];//保存入度
int graph[30][30];//是否有边
char output[30];//输出可确定序列
bool ok;//可以被确定
bool dilemma;//有环,矛盾
bool no;//不能被确定
char c1,c,c2;//输入
int topo(int n)
{
int in[30];
for(int i=0;i<n;i++)
in[i]=indegree[i];//使用备用数组进行拓扑排序
stack<int>s;//入度为0的点进栈
for(int i=0;i<n;i++)
if(!in[i])
s.push(i);
bool flag=0;//栈里面入度为0的元素大于一个时,不确定的拓扑排序
int cnt=0;//入度为0的元素个数,也是输出序列里面的个数
while(!s.empty())
{
if((s.size())>1)
flag=1;//不确定
int first=s.top();
s.pop();
output[cnt++]=first+'A';//放入输出序列里面
for(int i=0;i<n;i++)
if(graph[first][i])//与入度为0的元素相连的元素
{
in[i]--;
if(in[i]==0)
s.push(i);//入栈
}
}
if(cnt!=n)//如果没有环的话,序列里面的元素个数肯定等于输入的元素个数,就算在某个元素未输入之前,它的入度也初始化为0
return 2;//有环
else if(flag==1)//不确定的拓扑排序
return -1;
return 1;
}
int main()
{
int n,m;
while(cin>>n>>m&&(n||m))
{
ok=0;dilemma=0;no=0;
memset(indegree,0,sizeof(indegree));
memset(graph,0,sizeof(graph));
for(int i=1;i<=m;i++)
{
cin>>c1>>c>>c2;//当出现矛盾或者通过一些条件可被确定序列,剩下的输入条件就不需要再处理了
if(!ok&&!dilemma)//没有环,没有确定的拓扑排序,这里的拓扑排序必须输入的字母都有。比如输入ABCD 那么只有AB不是确定的
{
int t1=c1-'A';
int t2=c2-'A';
if(graph[t2][t1])//双向边,有环,出现矛盾
{
cout<<"Inconsistency found after "<<i<<" relations."<<endl;
dilemma=1;//出现矛盾
continue;
}
if(!graph[t1][t2])
{
graph[t1][t2]=1;
indegree[t2]++;//入度++
}
int ans=topo(n);//确定返回1,有环返回2
if(ans==2)
{
cout<<"Inconsistency found after "<<i<<" relations."<<endl;
dilemma=1;
continue;
}
if(ans==1)
{
cout<<"Sorted sequence determined after "<<i<<" relations: ";
for(int k=0;k<n;k++)
cout<<output[k];
cout<<"."<<endl;
ok=1;
}
}
}
if(!ok&&!dilemma)
cout<<"Sorted sequence cannot be determined."<<endl;
}
return 0;
}
E题;
基础题,直接套用模板,注意输出的处理,以及数组的初始化;
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 505;
int indeg[MaxN], ans[MaxN];
bool graph[MaxN][MaxN];
int n, m;
int main ()
{
while(~scanf("%d%d", &n, &m)){
int a, b;
memset(indeg, 0, sizeof(indeg));
memset(graph, 0, sizeof(graph));
for (int i=0; i<m; i++){
scanf("%d%d", &a, &b);
if(graph[a][b] == false){
graph[a][b] = true;
indeg[b] ++;
}
}
for(int i=0; i<n; i++){
if(i) printf(" ");
for (int j=1; j<=n; j++){
if(indeg[j] == 0){
printf("%d", j);
indeg[j]--;
for(int k=1; k<=n; k++){
if(graph[j][k])
indeg[k]--;
}
break;
}
}
}
printf("\n");
}
return 0;
}
C题:
这道题坑点比较多:
1.题目中要求越小的尽量越靠前,因此正向拓扑排序的结果是错的, 比如<1, 4>,<4, 2,><3, 5>;
2.不考虑重边的情况会错;
3.题中要求的输出是输出每一个编号的位置,不是按位置输出编号(题都没看懂的表示很伤心)。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 213;
bool graph[MaxN][MaxN];
int indeg[MaxN];
int ans[MaxN];
int n, m;
int main ()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
memset(graph, 0, sizeof(graph));
memset(indeg, 0, sizeof(indeg));
int a, b, ansi = n;
for(int i=0; i<m; i++){
scanf("%d%d", &a, &b);
if(!graph[b][a]){
graph[b][a] = true;
indeg[a]++;
}
}
int flag = 0;
for(int i=0; i<n; i++){
flag = 0;
for(int j=n; j>0; --j){
if(indeg[j] == 0){
indeg[j]--;
flag = 1;
ans[j] = ansi;
--ansi;
for(int k=n; k>0; --k){
if(graph[j][k]) indeg[k]--;
}
break;
}
}
if(flag == 0) break;
}
if(flag == 0) printf("-1\n");
else{
for(int i=1; i<=n; ++i){
if(i > 1)printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
}
return 0;
}