洛谷 P1347 排序 题解

2021-08-02

15:50:19

链接:

https://www.luogu.com.cn/problem/P1347

 

题目内容:

一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列 A,B,C,D 表示A<B,B<C,C<D。在这道题中,我们将给你一系列形如 A<B 的关系,并要求你判断是否能够根据这些关系确定这个数列的顺序。

输入格式

第一行有两个正整数 n,m,n 表示需要排序的元素数量,2≤n≤26,第 1 到 n 个元素将用大写的 A,B,C,D… 表示。m 表示将给出的形如 A<B 的关系的数量。

接下来有 m 行,每行有 3 个字符,分别为一个大写字母,一个 < 符号,一个大写字母,表示两个元素之间的关系。

输出格式

若根据前 x 个关系即可确定这 n 个元素的顺序 yyy..y(如 ABC),输出

Sorted sequence determined after xxx relations: yyy...y.

若根据前 x 个关系即发现存在矛盾(如 A<B,B<C,C<A),输出

Inconsistency found after x relations.

若根据这 m 个关系无法确定这 n 个元素的顺序,输出

Sorted sequence cannot be determined.

(提示:确定 n 个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)

输入输出样例

输入 #1
4 6
A<B
A<C
B<C
C<D
B<D
A<B
输出 #1
Sorted sequence determined after 4 relations: ABCD.
输入 #2
3 2
A<B
B<A
输出 #2
Inconsistency found after 2 relations.
输入 #3
26 1
A<Z
输出 #3
Sorted sequence cannot be determined.

说明/提示

2≤n≤26,1≤m≤600。

 

分析:

看题干我们知道,A<B等价与从A指向B的一条边,所以这一题可以用拓扑排序做。

接着我们看输出格式:

若根据前 x 个关系即可确定这 n 个元素的顺序 yyy..y(如 ABC),输出

Sorted sequence determined after xxx relations: yyy...y.

即:若在前x个关系式中满足题目,则输出“Sorted sequence determined after x relations: ABC...”

------------------------------------------------------------------------------

若根据前 x 个关系即发现存在矛盾(如 A<B,B<C,C<A),输出

Inconsistency found after x relations.

由案例说明,存在A<B,B<C,C<A时,即图内存在环,存在环的情况下就要输出“Inconsistency found after x relations.”

-------------------------------------------------------------------------------

若根据这 m 个关系无法确定这 n 个元素的顺序,输出

Sorted sequence cannot be determined.

由第三个样例,在仅输入A<Z的情况下,我们得不到其他字母的大小关系,所以输出

(提示:确定 n 个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)

 

再看本题的数据范围,由于全部是大写字母,所以最多不超过26个,数据过小,我们可以瞎搞暴力一下下

我们采取这样的方法:每输入一次  “?<?”  ,就用函数判断一次,如果符合三种情况中的任意一种,那么就输出

 

 

代码实现:

先处理输入,第一行输入n,m,那么

#include <iostream>
using namespace std;
const int N = 100;
int n,m;
int main() {
	cin>>n>>m;
	return 0;
}

 输入了n,m后,我们需要处理了剩下的m行数据

在上面我们提到,我们每输入一行数据,就要用函数判断一次,同时我们在输入"A<B"这种数据的时候,先把大写字母映射到数字上,所以我们写一个函数get(char ch),并且,我们用vector<int>vec[N]储存每个数下一级都有谁。每次输入时,比如“A<B”,就相当于从A引一条有向线到B,B作为接收的点,它的入度rudu[ ]肯定要加1,入度我们使用rudu[ ]来储存,在接下来的topo()函数里面有用处。

#include <iostream>
using namespace std;
const int N = 100;
int n,m;
vector<int> vec[N];
int rudu[N];
bool st[N];

int get(char ch){
    return ch-'A';
}


int main() {
	cin>>n>>m;
	for(int i = 1; i <= m; i++) {
		char c[3];
		cin>>c[0]>>c[1]>>c[2];
		int x = get(c[0]), y = get(c[2]);
		vec[x].push_back(y);
		rudu[y]++;
		if(!topo(i)) {
			cout<<"Inconsistency found after "<<i<<" relations.";
			return 0;
		}
		memset(st, false, sizeof st);
	}
	return 0;
}

  

接下来写核心函数 topo()

我们先写一个框架

 

bool topo(int r){
    
}

 

 

这里的 topo函数是有参数r的,r代表当前已经到第几个点了

然后接着,我们使用队列queue<int>q来维护,在函数内定义

 

bool topo(){
  queue<int>q;
      
}

  

接着,我们需要遍历入度数组rudu[N],并用一个临时数组 t[N] 储存一下,防止原数组在函数运行过程中被破坏,在遍历过程中,顺便将所有入度为0的点加入队列并且将这个点标记一下。随后,while(队列的长度),只要队列不空,就能一直循环下去,直至所有点被遍历。

但是在题目的第二种情况下,如果出现环,那么函数遍历的点数就会小于n,我们可以利用可以利用这一点来判断第二种情况,所以我们得定义一个变量来给函数遍历的点计数,命名为num。

还要设置一个flag来标记整个topo(int r)的情况(可以举个栗子:从A->B->C->.....->Z,读者可以自己枚举一下每次topo(int r)中flag的状态)。

 

bool topo(int r) {
        queue<int> q;
	int num = 0;
	bool flag = true;
	int t[N];
	for(int i = 0; i < n; i++) {
		t[i] = rudu[i];
		if(!rudu[i]) q.push(i), st[i] = true;
	}
	while(q.size()) {
		if(q.size() > 1) flag = false;
		int k = q.front();
		a[num++] = k; 
		q.pop();
		for(int i = 0; i < vec[k].size(); i++) t[vec[k][i]]--;
		for(int i = 0; i < n; i++) 
            if(!t[i] && !st[i]) q.push(i), st[i] = true;;
	}
	if(num < n) return false;
	if(flag && !ans) ans = r;
	return true;
}

  

最后再看看第一和第三种情况:

第一种情况,要用到函数结尾的ans,如果非0,则函数返回的是true,那么就是说前ans个字母可以按顺序升序输出,所以输出“Sorted sequence determined after ans relations: ”,然后将存在a[N]数组里面的字母一个个输出。

最后一种情况最好判断,直接else 输出就行了

所以完整代码实现如下:

 

#include <iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int N = 100;
int n,m,ans;
vector<int> vec[N];
int rudu[N],a[N];
bool st[N];
int get(char ch){
    return ch-'A';
}

bool topo(int r) {
    queue<int> q;
	int num = 0;
	bool flag = true;
	int t[N];
	for(int i = 0; i < n; i++) {
		t[i] = rudu[i];
		if(!rudu[i]) q.push(i), st[i] = true;
	}
	while(q.size()) {
		if(q.size() > 1) flag = false;
		int k = q.front();
		a[num++] = k; 
		q.pop();
		for(int i = 0; i < vec[k].size(); i++) t[vec[k][i]]--;
		for(int i = 0; i < n; i++) 
            if(!t[i] && !st[i]) q.push(i), st[i] = true;;
	}
	if(num < n) return false;
	if(flag && !ans) ans = r;
	return true;
}

int main() {
	cin>>n>>m;
	for(int i = 1; i <= m; i++) {
		char c[3];
		cin>>c[0]>>c[1]>>c[2];
		int x = get(c[0]), y = get(c[2]);
		vec[x].push_back(y);
		rudu[y]++;
		if(!topo(i)) {
			cout<<"Inconsistency found after "<<i<<" relations.";
			return 0;
		}
		memset(st, false, sizeof st);
	}
	if(ans) {
		cout<<"Sorted sequence determined after "<<ans<<" relations: ";
		for(int i = 0; i < n; i++) cout<<char(a[i] + 'A');
		cout<<".";
	}
	else cout<<"Sorted sequence cannot be determined.";
	return 0;
}

 

  2021-08-02

16:52:26

 

上一篇:如何把github项目搞到服务器上并打包成镜像运行起来


下一篇:opendaylight+mininet+openswitch构建SDN网络