• 2-SAT 问题及图论解法


    定义 给定 n 个 bool 型变量和 m 个关系式,形如 (x_i) 或(非) (x_j)。求问是否矛盾,不矛盾则需要求出一组解。

    解法 建立一个 (2n) 个节点的有向图。第 (2i-1) 与第 (2i) 个节点分别表示 (x_i) 为真与 (x_i) 为假。如果是 (x_i)(x_j) 在有向图中从 (x_i) 假连向 (x_j) 真,并从 (x_j) 假连向 (x_i) 真,表示二者中至少有一个为真,其他情况类似。然后求整个图的强连通分量。如果 (x_i) 假与 (x_i) 真在同一强连通分量中则矛盾。如果不矛盾,则如果 (x_i) 为真所在的强连通分量的拓扑序在 (x_i) 为假的强连通分量前则 (x_i) 为真即可,正确性显然,而拓扑序其实就是 tarjan 算法里面标好的每个强连通分量的前后值,不过是反的罢了。复杂度 (O(n+m))

    洛谷板子题

    #include<cstdio>
    #include<vector>
    
    const int maxn = 1E+6 + 5;
    
    int n, m, ind, cnt;
    int dfn[maxn], low[maxn];
    int top, sta[maxn], scc[maxn];
    bool insta[maxn];
    std::vector<int> to[maxn];
    
    void DFS(int u) {
    	dfn[u] = low[u] = ++ind;
    	sta[++top] = u, insta[u] = 1;
    	
    	for(auto v : to[u]) {
    		if(!dfn[v]) DFS(v), low[u] = std::min(low[u], low[v]);
    		else if(insta[v]) low[u] = std::min(low[u], dfn[v]);
    	}
    	
    	if(low[u] == dfn[u]) {
    		++cnt;
    		while(top >= 1 && sta[top] != u) {
    			insta[sta[top]] = 0;
    			scc[sta[top--]] = cnt;
    		}
    		insta[sta[top]] = 0;
    		scc[sta[top--]] = cnt;
    	}
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i = 1, x, y, a, b; i <= m; ++i) {
    		scanf("%d%d%d%d", &x, &a, &y, &b);
    		
    		to[2 * x - (a ^ 1)].push_back(y * 2 - b);
    		to[2 * y - (b ^ 1)].push_back(x * 2 - a);
    	}
    	
    	for(int i = 1; i <= n * 2; ++i)
    		if(!dfn[i]) DFS(i);
    	
    	for(int i = 1; i <= n; ++i)
    		if(scc[i * 2 - 1] == scc[i * 2])
    			return puts("IMPOSSIBLE"), 0;
    	
    	puts("POSSIBLE");
    	for(int i = 1; i <= n; ++i)
    		printf("%d ", scc[i * 2] < scc[i * 2 - 1]);
    }
    
  • 相关阅读:
    帆软报表实现全选全不选的功能
    knowledge_others
    skills_kafka
    skills_operation
    problems_others
    skills_windows
    c语言标识符
    快速排序法
    字符串处理scanf("%d%*c",&n);
    Byte.parseByte(String s,int radix)的解释
  • 原文地址:https://www.cnblogs.com/whx1003/p/13543820.html
Copyright © 2020-2023  润新知