题目大意:
有 n n n个未知数 { x n } \{x_n\} {xn}序列,其中有 m m m对小于关系,给 x 1 , x 2 , . . , x n x_1,x_2,..,x_n x1,x2,..,xn分别分配 ∀ \forall ∀或者 ∃ \exist ∃(分配的符号标记为 Q i Q_i Qi),使得 Q 1 x 1 Q 2 x 2 . . . Q n x n Q_1x_1\,Q_2x_2\,...\,Q_nx_n Q1x1Q2x2...Qnxn能够满足 m m m对小于关系(注意,量词的顺序是会影响句子意思,一定要按照上述顺序),且使 ∀ \forall ∀最多,如果不存在,则输出-1
解题思路:
- 将 a < b a<b a<b 替换成图上的 a → b a \rightarrow b a→b,那么就能构成一幅有向图
- 对于不存在的情况,则是图上有环,直接用拓扑排序判断即可
- 观察1号点,如果当前1号点为
∃
\exist
∃时,从该点沿着正(反)向边到达的所有点都必须为
∃
\exist
∃
如果1号点为 ∀ \forall ∀,那么从该点沿着正(反)向边到达的所有点也都必须为 ∃ \exist ∃ - 所以最终只要按顺序对没遍历过的点就 ∀ \forall ∀,否则就为 ∃ \exist ∃,对所有点都正着遍历一遍,反着遍历一遍即可
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 10;
vector <pii> G[maxn];
int n, m, id[maxn], in[maxn], cnt[maxn];
char ans[maxn];
void dfs(int u, int p, int bj) {
for (auto np : G[u]) {
if (np.sd != p) continue;
if (!id[np.ft] || id[np.ft] > 0 && p < 0 || id[np.ft] < 0 && p > 0) {
//三种情况,1. 当前点没遍历过
//2. 当前点正着遍历过,但现在是反着遍历到该点,
//3. 当前点反着遍历过,但现在是正着遍历到该点,
if (cnt[np.ft] >= 2) continue; //一个点最多遍历两次
id[np.ft] = bj;
cnt[np.ft]++;
dfs(np.ft, p, bj);
}
}
}
queue <int> q;
bool tuopu() {
int num = 0;
for (int i = 1; i <= n; i++) if (!in[i]) q.push(i), num++;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto np : G[u]) {
if (np.sd == -1) continue;
in[np.ft]--;
if (!in[np.ft]) q.push(np.ft), num++;
}
}
return (num == n);
}
int main() {
cin >> n >> m;
for (int i = 1, j, k; i <= m; i++) {
cin >> j >> k;
G[j].pb({k, 1});
G[k].pb({j, -1});
in[k]++;
}
int cnt = 0;
if (!tuopu()) {
puts("-1");
return 0;
}
for (int i = 1; i <= n; i++) {
if (id[i] == 0) {
id[i] = i;
cnt++;
dfs(i, 1, i);
dfs(i, -1, -i);
ans[i] = 'A';
}
else if (id[i] < 0) {
dfs(i, 1, i);
ans[i] = 'E';
}
else if (id[i] > 0) {
dfs(i, -1, -i);
ans[i] = 'E';
}
}
cout << cnt << endl;
for (int i = 1; i <= n; i++)
cout << ans[i];
cout << endl;
return 0;
}