社区讨论

拓扑排序+并查集,只有40分,求助各位巨佬,明天就考了

P9869[NOIP2023] 三值逻辑参与者 1已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@miim6gb1
此快照首次捕获于
2025/11/28 16:42
3 个月前
此快照最后确认于
2025/11/29 15:10
3 个月前
查看原帖
CPP
#include <bits/stdc++.h>
using namespace std;
int c, t, n, m, _i, _j, result;
char v;
//并查集查找和合并函数 
int find(int *DSU, const int x) {
    return x == DSU[x] ? x : DSU[x] = find(DSU, DSU[x]);
}
void merge(int *DSU, const int x, const int y) {
    const int i = find(DSU, x), j = find(DSU, y);
    if (i != j) DSU[i] = j;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> c >> t;
    while (t--) {
    	result = 0;
        cin >> n >> m;
        int DSU[n + 1];
        for (int i = 0; i <= n; ++i) DSU[i] = i;
        int father[n + 1] = {}, indegree[n + 1] = {};
        bool is_reversed[n + 1] = {}, is_visited[n + 1] = {};
        char value_list[n + 1] = {};
        queue<int> q;
        while (m--) {
            cin >> v;
            if (v == '+') {
                cin >> _i >> _j;
                if (value_list[_j] != '\0') {
                	father[_i] = 0;
                	is_reversed[_i] = false;
					value_list[_i] = value_list[_j];
				} else {
                	father[_i] = _j;
                	is_reversed[_i] = false;
					value_list[_i] = '\0';
                }
            } else if (v == '-') {
                cin >> _i >> _j;
                if (value_list[_j] != '\0') {
                	father[_i] = 0;
                	is_reversed[_i] = false;
                    if (value_list[_j] == 'T') value_list[_i] = 'F';
                    else if (value_list[_j] == 'F') value_list[_i] = 'T';
                    else value_list[_i] = 'U';
                } else {
                	father[_i] = _j;
                	is_reversed[_i] = true;
					value_list[_i] = '\0';
                }
            } else {
                cin >> _i;
            	father[_i] = 0;
            	is_reversed[_i] = false;
                value_list[_i] = v;
            }
        }
        for (int i = 1; i <= n; ++i) {
        	if (father[i] == 0) continue;
        	merge(DSU, i, father[i]);
        	indegree[father[i]]++;
		}
		//拓扑排序去除非环边 
        for (int i = 1; i <= n; ++i) {
        	if (indegree[i] == 0 && father[i] != 0) {
				q.push(i);
				is_visited[i] = true;
			}
        }
        while (!q.empty()) {
        	const int front = q.front();
        	q.pop();
        	indegree[father[front]]--;
        	if (father[front] != 0 && indegree[father[front]] == 0) q.push(father[front]);
		}
        for (int i = 1; i <= n; ++i) {
        	if (is_visited[i] || indegree[i] == 0) continue;
        	//遍历所有环 
        	int reverse_cnt = 0;
        	bool is_started = false;
        	int j = i;
        	while (!is_started || j != i) {
        		if (!is_started) is_started = true;
        		reverse_cnt += is_reversed[j];
        		is_visited[j] = true;
        		j = father[j];
			}
			//如果环上反转次数为奇数,将与环连通的所有节点设为U 
			if (reverse_cnt % 2 != 0) value_list[find(DSU, i)] = 'U';
        }
        for (int i = 1; i <= n; ++i) {
        	if (value_list[find(DSU, i)] == 'U' || value_list[i] == 'U') result++;
        }
        cout << result << endl;
    }
	return 0;
}

回复

1 条回复,欢迎继续交流。

正在加载回复...