先象征性地描述一下问题:一组(或者一个)东西有且仅有两种选择,要么选这个,要么选那个,还有一堆的约束条件

图论问题,当然是建边跑图喽

给出模型:

模型一:两者(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

题目POJ3683

然后说一下这个题的意思:

如果某两个婚礼进行仪式的时间有重合

那么就存在了矛盾关系,通过这些关系连边

Tarjan缩点重新建图(这里建反向图),判断

将一个未着色点 x 上色同时,把与它矛盾的点 y 以及 y 的所有子孙节点上另外一种颜色

上色完成后,进行拓扑排序,选择一种颜色的点输出就是一组可行解

介绍一下实现:

int n,cnt,scc,ind,top;
int a[maxn],b[maxn],belong[maxn],op[maxn];
bool inq[maxn];int dfn[maxn],low[maxn],q[maxn],col[maxn];
int g[maxn],gd[maxn],d[maxn];
struct Edge{int t,next;}e[maxm],ed[maxm];

ind是自增的用来记录dfn,scc是连通分量个数

belong用于存每一个点属于哪一个连通分量

然后op用来记录同一组的互斥条件

col用来存颜色

d用来存点的度数,便于拓扑排序

下面给出完整实现,感觉这个题可以很好地拆成几个很好地模板(就比如说拓扑排序,重新建图,强连通缩点,哈哈)

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=;
const int maxm=;
int n,cnt,scc,ind,top;
int a[maxn],b[maxn],belong[maxn],op[maxn];
bool inq[maxn];int dfn[maxn],low[maxn],q[maxn],col[maxn];
int g[maxn],gd[maxn],d[maxn];
struct Edge{int t,next;}e[maxm],ed[maxm];
void addedge(int u,int v)
{
e[++cnt].t=v;e[cnt].next=g[u];
g[u]=cnt;
}
void addedge2(int u,int v)
{
d[v]++;
ed[++cnt].t=v;ed[cnt].next=gd[u];
gd[u]=cnt;
}
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>'') {if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
//a[2i]-b[2i]前半程
//a[2i-1]-b[2i-1]后半程
bool jud(int x,int y)
{
if(b[x]<=a[y]||a[x]>=b[y]) return ;
return ;
}
void build()
{
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
{
if(jud(*i,*j))
{
addedge(*i,*j-);
addedge(*j,*i-);
}
if(jud(*i,*j-))
{
addedge(*i,*j);
addedge(*j-,*i-);
}
if(jud(*i-,*j))
{
addedge(*i-,*j-);
addedge(*j,*i);
}
if(jud(*i-,*j-))
{
addedge(*i-,*j);
addedge(*j-,*i);
}
}
}
void tarjan(int x)
{
//cout<<x<<endl;
dfn[x]=low[x]=++ind;
q[++top]=x;inq[x]=;
for(int tmp=g[x];tmp;tmp=e[tmp].next)
if(!dfn[e[tmp].t])
{
tarjan(e[tmp].t);
low[x]=min(low[e[tmp].t],low[x]);
}
else if(inq[e[tmp].t])
low[x]=min(dfn[e[tmp].t],low[x]);
if(low[x]==dfn[x])
{
int temp=;scc++;
while(temp!=x)
{
temp=q[top--];
inq[temp]=;
belong[temp]=scc;
}
}
}
void rebuild()
{
cnt=;
for(int x=;x<=*n;x++)
for(int tmp=g[x];tmp;tmp=e[tmp].next)
if(belong[x]!=belong[e[tmp].t])
{
//cout<<belong[e[tmp].t]<<" "<<belong[x]<<endl;
addedge2(belong[e[tmp].t],belong[x]);
} }
void dfs(int x)
{
if(col[x]) return;
col[x]=-;
for(int tmp=gd[x];tmp;tmp=ed[tmp].next)
dfs(ed[tmp].t);
}
void topsort()
{
for(int i=;i<=scc;i++)
if(!d[i]) q[++top]=i;
while(top)
{
int temp=q[top--];
//cout<<temp<<endl;
if(col[temp]) continue;
col[temp]=;dfs(op[temp]);
for(int tmp=gd[temp];tmp;tmp=ed[tmp].next)
{
d[ed[tmp].t]--;
if(!d[ed[tmp].t]) q[++top]=ed[tmp].t;
}
}
}
void print(int x)
{
printf("%.2d:",x/);
printf("%.2d ",x%);
}
int main()
{
n=read();
int x;
for(int i=;i<=n;i++)
{
//a[2i]-b[2i]前半程
//a[2i-1]-b[2i-1]后半程
a[*i]=read();
a[*i]=a[*i]*+read();
b[*i-]=read();
b[*i-]=b[*i-]*+read();
x=read();
b[*i]=a[*i]+x;
a[*i-]=b[*i-]-x;
}
build();
for(int i=;i<=*n;i++)
if(!dfn[i]) tarjan(i);
for(int i=;i<=n;i++)
if(belong[*i]==belong[*i-])
{puts("NO");return ;}
puts("YES");
rebuild();
for(int i=;i<=n;i++)
{
op[belong[*i]]=belong[*i-];
op[belong[*i-]]=belong[*i];
}
topsort();
for(int i=;i<=n;i++)
if(col[belong[*i]]==)
print(a[*i]),print(b[*i]),puts("");
else print(a[*i-]),print(b[*i-]),puts("");
return ;
}

图论:2-SAT的更多相关文章

  1. [leetcode] 题型整理之图论

    图论的常见题目有两类,一类是求两点间最短距离,另一类是拓扑排序,两种写起来都很烦. 求最短路径: 127. Word Ladder Given two words (beginWord and end ...

  2. 多边形碰撞 -- SAT方法

    检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...

  3. 并查集(图论) LA 3644 X-Plosives

    题目传送门 题意:训练指南P191 分析:本题特殊,n个物品,n种元素则会爆炸,可以转移到图论里的n个点,连一条边表示u,v元素放在一起,如果不出现环,一定是n点,n-1条边,所以如果两个元素在同一个 ...

  4. NOIp 2014 #2 联合权值 Label:图论 !!!未AC

    题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...

  5. HDU 5521 [图论][最短路][建图灵感]

    /* 思前想后 还是决定坚持写博客吧... 题意: n个点,m个集合.每个集合里边的点是联通的且任意两点之间有一条dis[i]的边(每个集合一个dis[i]) 求同时从第1个点和第n个点出发的两个人相 ...

  6. SDUT 2141 【TEST】数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历

    数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem ...

  7. [转] POJ图论入门

    最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意: ...

  8. HDU 5934 Bomb 【图论缩点】(2016年中国大学生程序设计竞赛(杭州))

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

  9. Codeforces 553C Love Triangles(图论)

    Solution: 比较好的图论的题. 要做这一题,首先要分析love关系和hate关系中,love关系具有传递性.更关键的一点,hate关系是不能成奇环的. 看到没有奇环很自然想到二分图的特性. 那 ...

  10. 图论(floyd算法):NOI2007 社交网络

    [NOI2007] 社交网络 ★★   输入文件:network1.in   输出文件:network1.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 在社交网络( ...

随机推荐

  1. C++11中default的使用

    In C++11, defaulted and deleted functions give you explicit control over whether the special member ...

  2. No resources found. Error from server (NotAcceptable): unknown (get pods)

    问题:正确安装kubectl后,可查询到当前使用集群服务,也可切换不同的集群,但无法获取当前运行的pods的信息与所有的service,具体表现为 $ kubectl get po -nwx No r ...

  3. C# 删除文件错误 access denied

    使用以下代码正常删除整个文件夹内容时,报错如下: if (backupPathDir.Exists) { System.IO.DirectoryInfo di = new DirectoryInfo( ...

  4. LAXCUS对数据存储的优化

        LAXCUS兼容行存储(NSM)和列存储(DSM)两种数据模型,实现了混合存储.同时在分布环境里,做到将数据的分发和备份自动处理,这样就不再需要人工干预了.     行存储,为了兼容广大用户对 ...

  5. Docker安装Zabbix全记录

    零.Zabbix架构设计 一.docker安装mysql 查找Docker Hub上的mysql镜像: [root@10e131e69e15 ~]# docker search mysql INDEX ...

  6. PAT——乙级1015/甲级1062:德才论

    这两个题是一模一样的 1015 德才论 (25 point(s)) 宋代史学家司马光在<资治通鉴>中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德 ...

  7. errno -4058 and npm WARN enoent ENOENT 解决方案

    1.报错如下: npm WARN checkPermissions Missing write access to C:\Users\hejinrong\AppData\Roaming\npm\nod ...

  8. kvm-1

    yum install libvirt* virt-* qemu-kvm* -y systemctl start libvirtd.service systemctl status libvirtd. ...

  9. 编程练习:寻找发帖"水王"

    题目: 寻找发帖"水王" 来源: 编程之美 分析 衍生:就是给定一个数组,其中某个元素出现次数超过了数组长度的一半,找出这个元素 方法s 方法1 对这个串进行遍历,同时对出现的元素 ...

  10. linux文件系统(ext2)

    一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如某种mkfs命令)格式化成某种格式的文件系统,然后才能存储文件,格式化的过程会在磁盘上写一些管理存储布局的信息.下图是一个磁盘分区格式化成e ...