这道题是我对于2-SAT问题的入门题:http://poj.org/problem?id=3207

一篇非常非常非常好的博客,很详细,认真看一遍差不多可以了解个大概:https://blog.csdn.net/JarjingX/article/details/8521690

总结一下我对于 2-SAT 问题的初步见解:

有很多个集合,每个集合里面有若干元素,现给出一些取元素的规则,要你判断是否可行,可行则给出一个可行方案。如果所有集合中,元素个数最多的集合有k个,那么我们就说这是一个k-sat问题,同理,2-sat问题就是k=2时的情况。

通常我们需要将集合中点之间的边转化成点, 再将点转化成多条新边, 这些新边就要看问题是属于哪类模型。

模型一:两者(A,B)不能同时取  

那么选择了A就只能选择B’,选择了B就只能选择A’  

连边A→B’,B→A’

模型二:两者(A,B)不能同时不取
那么选择了A’就只能选择B,选择了B’就只能选择A
连边A’→B,B’→A

模型三:两者(A,B)要么都取,要么都不取
那么选择了A,就只能选择B,选择了B就只能选择A,选择了A’就只能选择B’,选择了B’就只能选择A’
连边A→B,B→A,A’→B’,B’→A’

模型四:两者(A,A’)必取A

连边A’→A

题目大意:

一个圆环上有n个点, 点的序号从 0 到 n - 1, 给出m条边,说明点a, b之间有一条边相连接, 这条边可以在圆内部,也可以在圆的外部, 但边与边之间不能相交。求是否有满足的情况。

解题思路:

设对于一条边,在圆内部连接为i,圆外部连接为 i',那么两条理论上相交的边i, j(通过两条边的左右坐标来判断是否相交),就不能同时选择在圆的同一边。也就是模型一:两者(A, B)不能同时选。

注意的是 i'只是区别于i的一条对立边, 但是这条对立边不能影响到原来所存在的边, 这里我们可以用 i + m来表示 i 的对立边。

所以我们加边为 ,add(i,j + m), add(i + m, j), add(j, i + m), add(j + m, i)

然后再对 2 * m 个点(包括对立点)进行tarjan, 最后判断 m 个原始边的对立边是否处在同一个强连通分量中, 若存在处在同一个强连通分量中的,则无解,否则有解。

代码:

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std; int n, m; //n个点, m条边 ,点是从 0 到 n - 1
int l[], r[];
int cnt, head[];
int dfn[], low[], vis[], deep, color, belong[];
stack<int>S; void init()
{
mem(head, -);
cnt = ;
mem(dfn, );
mem(low, );
mem(vis, );
mem(belong, );
deep = ;
color = ;
} struct Edge
{
int to, next;
int from;
}edge[ * * ]; //要注意这个边的数量 void add(int a, int b)
{
edge[++ cnt].to = b;
edge[cnt].next = head[a];
head[a] = cnt;
} void tarjan(int now)
{
dfn[now] = low[now] = ++ deep;
vis[now] = ;
S.push(now);
for(int i = head[now]; i != -; i = edge[i].next)
{
int to = edge[i].to;
if(!dfn[to])
{
tarjan(to);
low[now] = min(low[now], low[to]);
}
else if(vis[to])
low[now] = min(low[now], dfn[to]);
}
if(dfn[now] == low[now])
{
color ++;
while()
{
int temp = S.top();
S.pop();
vis[temp] = ;
belong[temp] = color;
if(temp == now)
break;
}
}
} int main()
{
int flag = ;
init();
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i ++)
{
int a, b;
scanf("%d%d", &a, &b);
if(a > b)
swap(a, b);
l[i] = a, r[i] = b;//记录每条边的左端点和右端点,保证左小右大
}
for(int i = ; i < m; i ++) //建 2-SAT 图,将边转化成点处理
{ // A B不能同时存在的模型
for(int j = i + ; j <= m; j ++) //理论上有相交的边就转化成点来构造 2-SAT 问题的边
{
if(l[i] <= l[j] && r[i] >= l[j] && r[i] <= r[j] || l[i] >= l[j] && r[i] >= r[j] && l[i] <= r[j])
{
add(i, j + m);
add(i + m, j);
add(j, i + m);
add(j + m, i);
}
}
}
for(int i = ; i <= * m; i ++)//对于 i 边,其对立边为 i + m.每条边被看成点, 即总共有 2 * m个点
if(!dfn[i])
tarjan(i);
for(int i = ; i <= m; i ++)//点与对立点不能同时存在一个强连通分量中, 否则问题无解
{
int x = belong[i], y = belong[i + m];
if(x == y)
{
flag = ;
break;
}
}
if(flag)
printf("panda is telling the truth...\n");
else
printf("the evil panda is lying again\n");
return ;
}

POJ 3207 【2-SAT入门题 + 强连通分量】的更多相关文章

  1. POJ 3180 牛围着池塘跳舞 强连通分量裸题

    题意:一群牛被有向的绳子拴起来,如果有一些牛(>=2)的绳子是同向的,他们就能跳跃.求能够跳跃的组数. #include <iostream> #include <cstdio ...

  2. POJ 1236 Network of Schools(强连通分量/Tarjan缩点)

    传送门 Description A number of schools are connected to a computer network. Agreements have been develo ...

  3. POJ 2342 树形DP入门题

    有一个大学的庆典晚会,想邀请一些在大学任职的人来參加,每一个人有自己的搞笑值,可是如今遇到一个问题就是假设两个人之间有直接的上下级关系,那么他们中仅仅能有一个来參加,求请来一部分人之后,搞笑值的最大是 ...

  4. [poj 1904]King's Quest[Tarjan强连通分量]

    题意:(当时没看懂...) N个王子和N个女孩, 每个王子喜欢若干女孩. 给出每个王子喜欢的女孩编号, 再给出一种王子和女孩的完美匹配. 求每个王子分别可以和那些女孩结婚可以满足最终每个王子都能找到一 ...

  5. poj 1236 Network of Schools (强连通分量+缩点)

    题目大概: 每个学校都可以把软件复制好,交给它名单上的学校. 问题A:把软件复制成几份,然后交给不同的学校,所有学校才能够都有软件. 问题B:添加几条边,能使得这个图变成强连通图. 思路: 找出所有的 ...

  6. poj 1236 Network of Schools(又是强连通分量+缩点)

    http://poj.org/problem?id=1236 Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Su ...

  7. Electricity POJ - 2117 + SPF POJ - 1523 去除割点后求强连通分量个数问题

    Electricity POJ - 2117 题目描述 Blackouts and Dark Nights (also known as ACM++) is a company that provid ...

  8. POJ 1236 Network of Schools(强连通分量)

    POJ 1236 Network of Schools 题目链接 题意:题意本质上就是,给定一个有向图,问两个问题 1.从哪几个顶点出发,能走全全部点 2.最少连几条边,使得图强连通 思路: #inc ...

  9. POJ 3984(DFS入门题 +stack储存路径)

    POJ 3984 Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, ...

随机推荐

  1. Microsoft.Practices.Unity使用配置文件总是报错The type name or alias could not be resolved.

    Type name could not be resolved. Please check config file http://stackoverflow.com/questions/1493564 ...

  2. 洛谷P2110 欢总喊楼记

    洛谷题目链接 乱搞qwq 我们其实可以找规律,对于每个数$x$,我们先求出从$1$~$x$中有多少符合条件的,记为$sum[x]$,那么类似于前缀和,答案自然就是$sum[r]-sum[l-1]$了 ...

  3. Qbxt 模拟赛 Day4 T2 gcd(矩阵乘法快速幂)

    /* 矩阵乘法+快速幂. 一开始迷之题意.. 这个gcd有个规律. a b b c=a*x+b(x为常数). 然后要使b+c最小的话. 那x就等于1咯. 那么问题转化为求 a b b a+b 就是斐波 ...

  4. libpng warning: iCCP: known incorrect sRGB profile告警处理

    在 qt中加载某些 png图片会出现:libpng warning: iCCP: known incorrect sRGB profile   告警信息. 虽然没什么影响,但是总看到这个警告非常的不舒 ...

  5. 在linux上使用impdp命令时提示ORA-12154: TNS:could not resolve the connect identifier specified的问题

    今天在一台linux服务器上用impdp命令导入dmp文件时出现了错误: ORA: TNS:could not resolve the connect identifier specified 我使用 ...

  6. 空指针/0/NULL

    空指针/0/NULL 空指针是一个被赋值为0的指针,在没有被具体初始化之前,其值为0. NULL 是一个标准规定的宏定义,用来表示空指针常量. #define NULL 0   或者 #define ...

  7. Flume-Spooling Directory Source 监控目录下多个新文件

    使用 Flume 监听整个目录的文件,并上传至 HDFS. 一.创建配置文件 flume-dir-hdfs.conf https://flume.apache.org/FlumeUserGuide.h ...

  8. laravel-5.6路由命名

    1.第一种:通过route路由中的as关键字来实现 1 Route::get('api/user',['as'='web.user'],'messageController@userInformati ...

  9. Android即时通讯开发之XMPP (一)初识XMPP协议和asmack

    在讲XMPP和asmck之前 ,我还是先分享一些资源文档,如果你有耐心,可以直接忽略我下面所写的.下面有关XMPP的介绍大部分是摘抄网上的文档,后面我会写一些基于XMPP协议和asmck开源库的聊天室 ...

  10. MybatisUtil工具类的作用

    1)在静态初始化块中加载mybatis配置文件和StudentMapper.xml文件一次 2)使用ThreadLocal对象让当前线程与SqlSession对象绑定在一起 3)获取当前线程中的Sql ...