CF1344C Quantifier Question

16 篇文章 0 订阅

题目大意:

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 ab,那么就能构成一幅有向图
  • 对于不存在的情况,则是图上有环,直接用拓扑排序判断即可
  • 观察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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值