融合增减:

https://blog.csdn.net/qq_24451605/article/details/47126143

https://blog.csdn.net/u012915516/article/details/48442265

2 - SAT:

一个事物具有两面性,并且与其它事物存在约束关系

注意在建图的时候 不仅可以是在每次给出的两个间建边,还可以与其他的点建边

-------------------------------------------------对于2-sat问题的描述-------------------------------------------------

给出一个序列,每个数是一个bool值,给出一些限制关系,得到最终的可行解的问题叫做适应性问题,也就是sat问题,2-sat问题就是给出的限制最多是两两元素之间的限制。

这种适应性问题的解决,同样是能够抽象为我们已知的图论模型的。

--------------------------------------------------2-sat问题的建图方法--------------------------------------------------

1.我们利用一条有向边<i,j>,来表示选i的情况下,一定要选j;

2.用i表示某个点是true,那么i'表示某个点是false

3.因为限制的两两之间的关系,所以我们可以通过逻辑关系来建边:

在一些确定的关系中,要以确定的关系建边,可以为任意值的不建,只建有限制的(例 poj 2296 ),这种类型 要注意列出所有情况

 还有 就是要明确i和~i是什么 例如poj2296 是正方形在点的上边 还是下边   hdu1814 是i去还是i^1去 而不是 i去还是不去

若图中存在有向边i->j,则表示若选了i必须选j

默认下面的x  y都为1 也就是选择~~

And 结果为1:建边 ~x->x, ~y->y (两个数都为1)  

And 结果为0:建边 y->~x , x->~y(两个数至少有一个为0)

OR  结果为1:建边 ~x->y , ~y->x(两个数至少有一个为1)

OR  结果为0:建边 x->~x , y->~y(两个数都为0)

XOR 结果为1:建边 x->~y , ~x->y , ~y->x , y -> ~x (两个数一个为0,一个为1)

XOR 结果为0:建边 x->y , ~x->~y , y->x, ~y->~x(两个数同为1或者同为0)

这么建图之后,会出现一个有向图,这个有向图会导致一个连通环,导致某个点一旦选取,那么这条链上的所有点都要被选中。如果我们找到一个强连通分量,那么这个强连通分量当中的点,如果选取必须全部选取,不选取的话一定是全部不选取,所以只要满足这个有向图中连通的点不会导致i和i'同时被选取,如果不存在矛盾,那么当前问题就是有解的。但是往往在求解过程中,我们要求的解会要求一些性质,所以提供以下几种解决方案。

------------------------------------------------2-sat问题的解决方案--------------------------------------------------------

1.求字典序最小的解的方法:

暴力dfs求解(复杂度O(N*M))

就是蓝书上的代码就是了  栈中的顺序即保证了字典序最小

2.判断当前的2-sa问题t是否有解

tarjan强连通缩点,加判断(复杂度O(N+M))

就是判断u --> v 是否在同一个连通分量中

具体讲解见 伍昱:《由对称性解2-SAT问题》

 for(int i = ; i <  * n; i++)
if(!vis[i]) tarjan (i); for(int i = ; i < n; i++)
if(sccno[i << ] == sccno[i << | ] )
return false;
return true;

3.求出当前的2-sat问题的任意一组解

tarjan强连通缩点 + 反向建边 + 拓扑排序(染色) + 构建一组解(复杂度O(N+M))

选择一个没有被染色的点u 将其染成1 把所有与u点矛盾的点v和v的子孙染成2 不断重复操作 直到没有点可以染色而止

例题

Wedding

POJ - 3648

n对夫妻去参加婚礼

但有m对人有通奸关系,(也有可能同性),不能让新娘看到有通奸关系的两个人坐在一边,n对夫妻必须不能坐在一边

新娘带着超豪华的头饰,以至于她不能看到和她一遍的人,现在求一组和新娘坐在一边的人的解

意思就是 有通奸关系的可以一边一个 ,也可以都坐在新娘的那边 (因为她看不到)

也就是至少有一个1

#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <map>
#include <cctype>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <bitset>
#define rap(i, a, n) for(int i=a; i<=n; i++)
#define rep(i, a, n) for(int i=a; i<n; i++)
#define lap(i, a, n) for(int i=n; i>=a; i--)
#define lep(i, a, n) for(int i=n; i>a; i--)
#define rd(a) scanf("%d", &a)
#define rlld(a) scanf("%lld", &a)
#define rc(a) scanf("%c", &a)
#define rs(a) scanf("%s", a)
#define pd(a) printf("%d\n", a);
#define plld(a) printf("%lld\n", a);
#define pc(a) printf("%c\n", a);
#define ps(a) printf("%s\n", a);
#define MOD 2018
#define LL long long
#define ULL unsigned long long
#define Pair pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
//freopen("1.txt", "r", stdin);
using namespace std;
const int maxn = , INF = 0x7fffffff, LL_INF = 0x7fffffffffffffff;
int n, m;
vector<int> G[maxn];
vector<int> f[maxn];
int vis[maxn], low[maxn], sccno[maxn], scc_clock, scc_cnt;
int head[maxn], cnt, in[maxn],col[maxn], cft[maxn];
stack<int> S; void dfs(int u)
{
low[u] = vis[u] = ++scc_clock;
S.push(u);
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
if(!vis[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else if(!sccno[v])
low[u] = min(low[u], vis[v]);
}
if(vis[u] == low[u])
{
scc_cnt++;
for(;;)
{
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
} void bfs()
{
queue<int> Q;
for(int i = ; i <= scc_cnt; i++) //把入度为0的加入的队列中
if(!in[i])
Q.push(i);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
if(!col[u]) //染色
{
col[u] = ;
col[cft[u]] = ;
}
for(int i = ; i < f[u].size(); i++)
{
int v = f[u][i];
in[v]--; //删除与u相关的边
if(!in[v])
Q.push(v);
}
}
} void init()
{
for(int i = ; i < maxn; i++) f[i].clear(), G[i].clear();
while(!S.empty()) S.pop();
mem(head, -);
mem(vis, );
mem(sccno, );
mem(in, );
mem(col, );
cnt = scc_clock = scc_cnt = 0;
} int main()
{
while(cin >> n >> m && n + m)
{
init();
int x, y;
char a, b;
for(int i = ; i < m; i++)
{
scanf("%d%c%d%c", &x, &a, &y, &b);
if(a == 'w') x = * x;
else if(a == 'h') x = * x + ;
if(b == 'w') y = * y;
else if(b == 'h') y = * y + ;
G[x^].push_back(y);
G[y^].push_back(x);
}
G[].push_back();
for(int i = ; i < * n; i++)
{
if(!vis[i])
dfs(i);
}
int flag = ;
for(int i = ; i < n * ; i+=) //判断是否有解
{
int u = sccno[i], v = sccno[i + ];
if(u == v)
{
flag = ;
cout << "bad luck" << endl;
break;
}
cft[u] = v; //同时标记对立点
cft[v] = u;
}
if(flag) continue;
for(int i = ; i < n * ; i++) //建反向边
{
for(int j = ; j < G[i].size(); j++)
{
int u = sccno[i], v = sccno[G[i][j]];
if(u != v)
{
f[v].push_back(u);
in[u]++;
}
}
}
bfs(); //拓扑排序
for(int i = ; i < n * ; i+=)
{
if(i != ) cout << " ";
if(col[sccno[i]] == col[sccno[]]) cout << i/ << "w";
else cout << i/ << "h";
}
cout << endl;
} return ;
}

关于2-sat的建图方法及解决方案的更多相关文章

  1. HDU3572Task Schedule(最大流 ISAP比較快)建图方法不错

    Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  2. Leapin' Lizards HDU - 2732 (恶心的建图。。)

    这道题其实不难...就是建图恶心了点....emm... 题意: 多源多汇 + 拆边 青蛙跳柱子, 每根柱子都有一定的承载能力, 青蛙跳上去之后柱子的承载能力就会减一,跳到边界就能活 跳不到就over ...

  3. [Bzoj4289]PA2012 Tax(Dijkstra+技巧建图)

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...

  4. 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

    [BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...

  5. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

  6. POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)

    题意 : 给出一些牛棚,每个牛棚都原本都有一些牛但是每个牛棚可以容纳的牛都是有限的,现在给出一些路与路的花费和牛棚拥有的牛和可以容纳牛的数量,要求最短能在多少时间内使得每头牛都有安身的牛棚.( 这里注 ...

  7. hdu-4292.food(类dining网络流建图)

    Food Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

    [题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...

  9. 洛谷 P5331 - [SNOI2019]通信(CDQ 分治优化建图+费用流)

    题面传送门 首先熟悉网络流的同学应该能一眼看出此题的建模方法: 将每个点拆成两个点 \(in_i,out_i\),连一条 \(S\to in_i\),容量为 \(1\) 费用为 \(0\) 的边 连一 ...

随机推荐

  1. Django组件 之 ookie 和 session

    -----------------------------------------------------------------------------------------相信自己,水滴石穿,不 ...

  2. sql存储过程中使用 output、nvarchar(max)

    1.sql存储过程中使用 output CREATE PROCEDURE [dbo].[P_Max] @a int, -- 输入 @b int, -- 输入 @Returnc int output - ...

  3. 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)

    链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...

  4. Mike and gcd problem CodeForces - 798C (贪心思维+数论)

    题目链接 比较棒的一道题, 题意: 给你一个N个数的数组,让你用尽量少的操作使整个数组的gcd大于1,即gcd(a1 ,a2,,,,an) > 1 如果可以输出YES和最小的次数,否则输出NO ...

  5. Mike and strings CodeForces - 798B (简洁写法)

    题目链接 时间复杂度 O(n*n*|s| ) 纯暴力,通过string.substr()函数来构造每一个字符串平移后的字符串. #include <iostream> #include & ...

  6. Python是如何进行内存管理

    三个方面:一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数. 引用计数增加的情况: 1,一个对象分 ...

  7. Javascript模板引擎handlebars使用

    源地址:http://rfyiamcool.blog.51cto.com/1030776/1278620 代码示例: <!DOCTYPE html> <html> <he ...

  8. 记一个JS树结构路径查找

    var a=[ { "id" : "0000", "text" : "R1", "children" ...

  9. python实现满二叉树递归循环

    一.二叉树介绍点这片文章 二叉树及题目介绍 例题: 有一颗满二叉树,每个节点是一个开关,初始全是关闭的,小球从顶点落下, 小球每次经过开关就会把它的状态置反,这个开关为关时,小球左跑,为开时右跑.现在 ...

  10. #Leetcode# 836. Rectangle Overlap

    https://leetcode.com/problems/rectangle-overlap/ A rectangle is represented as a list [x1, y1, x2, y ...