目录
1.Problem
Logical quantifiers are very useful tools for expressing claims about a set. For this problem, let's focus on the set of real numbers specifically. The set of real numbers includes zero and negatives. There are two kinds of quantifiers: universal (∀∀) and existential (∃∃). You can read more about them here.
The universal quantifier is used to make a claim that a statement holds for all real numbers. For example:
- ∀x,x<100∀x,x<100 is read as: for all real numbers xx, xx is less than 100100. This statement is false.
- ∀x,x>x−1∀x,x>x−1 is read as: for all real numbers xx, xx is greater than x−1x−1. This statement is true.
The existential quantifier is used to make a claim that there exists some real number for which the statement holds. For example:
- ∃x,x<100∃x,x<100 is read as: there exists a real number xx such that xx is less than 100100. This statement is true.
- ∃x,x>x−1∃x,x>x−1 is read as: there exists a real number xx such that xx is greater than x−1x−1. This statement is true.
Moreover, these quantifiers can be nested. For example:
- ∀x,∃y,x<y∀x,∃y,x<y is read as: for all real numbers xx, there exists a real number yy such that xx is less than yy. This statement is true since for every xx, there exists y=x+1y=x+1.
- ∃y,∀x,x<y∃y,∀x,x<y is read as: there exists a real number yy such that for all real numbers xx, xx is less than yy. This statement is false because it claims that there is a maximum real number: a number yy larger than every xx.
Note that the order of variables and quantifiers is important for the meaning and veracity of a statement.
There are nn variables x1,x2,…,xnx1,x2,…,xn, and you are given some formula of the form
f(x1,…,xn):=(xj1<xk1)∧(xj2<xk2)∧⋯∧(xjm<xkm),f(x1,…,xn):=(xj1<xk1)∧(xj2<xk2)∧⋯∧(xjm<xkm),
where ∧∧ denotes logical AND. That is, f(x1,…,xn)f(x1,…,xn) is true if every inequality xji<xkixji<xki holds. Otherwise, if at least one inequality does not hold, then f(x1,…,xn)f(x1,…,xn) is false.
Your task is to assign quantifiers Q1,…,QnQ1,…,Qn to either universal (∀∀) or existential (∃∃) so that the statement
Q1x1,Q2x2,…,Qnxn,f(x1,…,xn)Q1x1,Q2x2,…,Qnxn,f(x1,…,xn)
is true, and the number of universal quantifiers is maximized, or determine that the statement is false for every possible assignment of quantifiers.
Note that the order the variables appear in the statement is fixed. For example, if f(x1,x2):=(x1<x2)f(x1,x2):=(x1<x2) then you are not allowed to make x2x2 appear first and use the statement ∀x2,∃x1,x1<x2∀x2,∃x1,x1<x2. If you assign Q1=∃Q1=∃ and Q2=∀Q2=∀, it will only be interpreted as ∃x1,∀x2,x1<x2∃x1,∀x2,x1<x2.
2.Input
The first line contains two integers nn and mm (2≤n≤2⋅1052≤n≤2⋅105; 1≤m≤2⋅1051≤m≤2⋅105) — the number of variables and the number of inequalities in the formula, respectively.
The next mm lines describe the formula. The ii-th of these lines contains two integers jiji,kiki (1≤ji,ki≤n1≤ji,ki≤n, ji≠kiji≠ki).
3.Output
If there is no assignment of quantifiers for which the statement is true, output a single integer −1−1.
Otherwise, on the first line output an integer, the maximum possible number of universal quantifiers.
On the next line, output a string of length nn, where the ii-th character is "A" if QiQi should be a universal quantifier (∀∀), or "E" if QiQi should be an existential quantifier (∃∃). All letters should be upper-case. If there are multiple solutions where the number of universal quantifiers is maximum, print any.
4.Examples
4.1input
2 1
1 2
4.2output
1
AE
5.Code
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template <typename T>
bool chkmax(T &x, T y) {
return x < y ? x = y, true : false;
}
template <typename T>
bool chkmin(T &x, T y) {
return x > y ? x = y, true : false;
}
int readint() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
int main() {
int n, m;
n = readint();
m = readint();
vector<int> du(n + 1, 0);
vector<int> q(n);
vector<int> min1(n + 1, INT_MAX);
vector<int> min2(n + 1, INT_MAX);
vector<char> ans(n + 1, 'E');
vector<bool> vis(n + 1, false);
vector<vector<int>> adj(n + 1);
for (int i = 1; i <= m; i++) {
int x, y;
x = readint();
y = readint();
adj[x].push_back(y);
du[y]++;
}
int front = 0, rear = 0;
for (int i = 1; i <= n; i++)
if (!du[i])
q[rear++] = i;
while (front < rear) {
int t = q[front++];
for (auto v : adj[t])
if (!(--du[v]))
q[rear++] = v;
}
if (rear < n)
return printf("-1\n"), 0;
for (int i = 0; i <= n - 1; i++)
for (auto v : adj[q[i]])
chkmin(min1[v], min(min1[q[i]], q[i]));
for (int i = n - 1; i >= 0; i--)
for (auto v : adj[q[i]])
chkmin(min2[q[i]], min(min2[v], v));
int cnt = 0;
for (int i = 1; i <= n; i++)
if (min1[i] > i && min2[i] > i)
ans[i] = 'A', cnt++;
printf("%d\n", cnt);
puts(ans.data() + 1);
return 0;
}
6.Conclusion
这段C++代码实现了一个图论算法,用于解决一种拓扑排序相关的问题。以下是主要功能和流程的简要介绍:
输入:
- 通过
readint
函数读取两个整数n
和m
,分别表示图中的节点数和边数。- 通过循环读取
m
条边,其中每条边连接两个节点。数据结构定义:
- 使用向量
du
记录每个节点的入度。- 使用向量
q
作为队列,用于拓扑排序。- 使用向量
min1
和min2
记录每个节点的前两小的值。- 使用字符向量
ans
记录每个节点的状态。图的建立和拓扑排序:
- 构建邻接表
adj
表示图的连接关系,并计算每个节点的入度。- 将入度为0的节点加入队列
q
,然后进行拓扑排序。拓扑排序过程:
- 使用队列
q
进行广度优先搜索,将每个出队的节点标记为已访问。- 对于每个出队的节点,更新其邻接节点的入度,若入度为0,则将其加入队列。
寻找前两小的值:
- 根据拓扑排序的结果,计算每个节点的前两小的值,并保存在
min1
和min2
中。确定节点状态:
- 根据计算得到的前两小的值,确定每个节点的状态,存储在字符向量
ans
中。输出结果:
- 输出满足条件的节点数和每个节点的状态。
总体而言,这段代码通过拓扑排序找到图中满足特定条件的节点,并输出相应的结果。