初涉2-SAT
2-SAT:有趣的图论模型
什么是2-SAT
SAT是适定性(Satisfiability)问题的简称。之所以研究2-sat是因为当k>2时,k-sat问题已经被证明是NPC的了。
2-sat问题简单来说就是有$n$个二元集合,其中一些元素不能同时取到,问每个集合各取一个的方案。
至于2-sat的算法,就是将不能同时取元素的限制转为有向边,再跑一遍tarjan(如果要求判断可行性);或者dfs判断是否冲突(求方案)。
难就难在建模吧……或者说其他难点我还没学会?
这里有一篇论文2-sat问题和一篇博客【研究总结】2-sat问题,先攒着吧……
一些例题
【小技巧转化】bzoj1823: [JSOI2010]满汉全席
Description
满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中。由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而能够烹饪出经过专家认证的满汉全席,也是中国厨师最大的荣誉之一。 世界满汉全席协会是由能够料理满汉全席的专家厨师们所组成,而他们之间还细分为许多不同等级的厨师。为了招收新进的厨师进入世界满汉全席协会,将于近日举办满汉全席大赛,协会派遣许多会员当作评审员,为的就是要在參赛的厨师之中,找到满汉料理界的明日之星。 大会的规则如下:每位參赛的选手可以得到n 种材料,选手可以自由选择用满式或是汉式料理将材料当成菜肴。大会的评审制度是:共有m 位评审员分别把关。每一位评审员对于满汉全席有各自独特的見解,但基本见解是,要有兩样菜色作为满汉全席的标志。如某评审认为,如果没有汉式东坡肉跟满式的涮羊肉锅,就不能算是满汉全席。但避免过于有主見的审核,大会规定一个评审员除非是在认为必备的两样菜色都没有做出來的狀况下,才能淘汰一位选手,否则不能淘汰一位參赛者。换句话說,只要參赛者能在这兩种材料的做法中,其中一个符合评审的喜好即可通过该评审的审查。如材料有猪肉,羊肉和牛肉时,有四位评审员的喜好如下表: 评审一 评审二 评审三 评审四 满式牛肉 满式猪肉 汉式牛肉 汉式牛肉 汉式猪肉 满式羊肉 汉式猪肉 满式羊肉 如參赛者甲做出满式猪肉,满式羊肉和满式牛肉料理,他将无法满足评审三的要求,无法通过评审。而參赛者乙做出汉式猪肉,满式羊肉和满式牛肉料理,就可以满足所有评审的要求。 但大会后來发现,在这样的制度下如果材料选择跟派出的评审员没有特别安排好的话,所有的參赛者最多只能通过部分评审员的审查而不是全部,所以可能会发生没有人通过考核的情形。如有四个评审员喜好如下表时,则不論參赛者采取什么样的做法,都不可能通过所有评审的考核: 评审一 评审二 评审三 评审四 满式羊肉 满式猪肉 汉式羊肉 汉式羊肉 汉式猪肉 满式羊肉 汉式猪肉 满式猪肉 所以大会希望有人能写一个程序來判断,所选出的m 位评审,会不会发生 没有人能通过考核的窘境,以便协会组织合适的评审团。
Input
第一行包含一个数字 K,代表测试文件包含了K 组资料。每一组测试资料的第一行包含兩个数字n 跟m(n≤100,m≤1000),代表有n 种材料,m 位评审员。为方便起見,材料舍弃中文名称而给予编号,编号分别从1 到n。接下來的m 行,每行都代表对应的评审员所拥有的兩个喜好,每个喜好由一个英文字母跟一个数字代表,如m1 代表这个评审喜欢第1 个材料透过满式料理做出來的菜,而h2 代表这个评审员喜欢第2 个材料透过汉式料理做出來的菜。每个测试文件不会有超过50 组测试资料
Output
每笔测试资料输出一行,如果不会发生没有人能通过考核的窘境,输出GOOD;否则输出BAD(大写字母)。
题目分析
感觉那年出题人……很亦可赛艇啊。
这里的二元组限制变成了必须选一种,但是实际上转化一下就是一样的。
例如m3和h1必须选一种,那么等价于选m3必选h1;选m1必选m3。于是直接用tarjan判断可行性就好了。
/**************************************************************
Problem: 1823
User: AntiQuality
Language: C++
Result: Accepted
Time:68 ms
Memory:1324 kb
****************************************************************/
#include<bits/stdc++.h>
const int maxn = ;
const int maxm = ;
int tt,n,m;
int tim,dfn[maxn],low[maxn];
int stk[maxn],cnt,col[maxn],cols;
int edgeTot,edges[maxm],nxt[maxm],head[maxn];
int read()
{
char ch = getchar();
int num = , fl;
for (; !isalpha(ch); ch = getchar());
fl = (ch=='h'?:n);
for (; !isdigit(ch); ch = getchar());
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
return num+fl;
}
inline int ene(int x){return x>n?x-n:x+n;}
void addedge(int u, int v)
{
edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++tim;
stk[++cnt] = u;
for (int i=head[u]; i!=-; i=nxt[i])
{
int v = edges[i];
if (!dfn[v])
tarjan(v), low[u] = std::min(low[u], low[v]);
else if (!col[v])
low[u] = std::min(low[u], dfn[v]);
}
if (dfn[u]==low[u]){
col[u] = ++cols;
for (; stk[cnt]!=u; cnt--)
col[stk[cnt]] = cols;
cnt--;
}
}
int main()
{
scanf("%d",&tt);
while (tt--)
{
edgeTot = cnt = cols = tim = ;
memset(head, -, sizeof head);
memset(dfn, , sizeof dfn);
memset(col, , sizeof col);
scanf("%d%d",&n,&m);
for (int i=; i<=m; i++)
{
int u = read(), v = read();
addedge(ene(u), v);
addedge(ene(v), u);
}
for (int i=; i<=*n; i++)
if (!dfn[i]) tarjan(i);
bool fl = ;
for (int i=; i<=n; i++)
if (col[i]==col[i+n]){
fl = ;
break;
}
if (fl) puts("GOOD");
else puts("BAD");
}
return ;
}
hdu1814Peaceful Commission
Problem Description
The Commission has to fulfill the following conditions:
1.Each party has exactly one representative in the Commission,
2.If two deputies do not like each other, they cannot both belong to the Commission.
Each party has exactly two deputies in the Parliament. All of them are numbered from 1 to 2n. Deputies with numbers 2i-1 and 2i belong to the i-th party .
Task
Write a program, which:
1.reads from the text file SPO.IN the number of parties and the pairs of deputies that are not on friendly terms,
2.decides whether it is possible to establish the Commission, and if so, proposes the list of members,
3.writes the result in the text file SPO.OUT.
Input
There are multiple test cases. Process to end of file.
Output
题目大意
有n个党派,每个党派只有2人,现要设立一个和平委员会,必须满足如下条件;
- 每个党派在委员会中恰有一个代表
- 如果两个代表互相反感,那么他们都不能属于委员会。
求可行性以及字典序最小方案
题目分析
嘛……最早我做的时候第一问用的tarjan缩点,第二问瞎搞:对于每一个入度为零的点先做一遍dfs以确定它之后以及它自己是否合法。
但是可能思路有点乱写挂了好久……花了好几个小时都没弄出来。
后来在网上发现一种比较好的思路:其实就是最上面提到的dfs方法。显而易见dfs过程中可以判断可行性,那么为什么还要去写个没什么其他用处的tarjan呢?
这里的dfs跟我最早想的dfs也一样(所以不清楚我到底哪里写挂),通过子节点合法性回溯回查找节点。不过这样总的来说就可以按照顺序进行而不用考虑乱七八糟的东西了。
bool dfs(int x)
{
if (vis[ene(x)]) return ;
if (vis[x]) return ;
vis[x] = , stk[++cnt] = x;
for (int i=head[x]; i!=-; i=nxt[i])
if (!dfs(edges[i])) return ;
return ;
}
这里是dfs判断的代码。
所以其实是60来行就可以搞定的事情。
#include<bits/stdc++.h>
const int maxn = ;
const int maxm = ; int n,m;
int edges[maxm],nxt[maxm],head[maxn],edgeTot;
int stk[maxn],cnt;
bool vis[maxn]; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
inline int ene(int x){return ((x-)^)+;}
void addedge(int u, int v)
{
edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
bool dfs(int x)
{
if (vis[ene(x)]) return ;
if (vis[x]) return ;
vis[x] = , stk[++cnt] = x;
for (int i=head[x]; i!=-; i=nxt[i])
if (!dfs(edges[i])) return ;
return ;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF&&n&&m)
{
memset(vis, , sizeof vis);
memset(head, -, sizeof head);
cnt = edgeTot = ;
for (int i=; i<=m; i++)
{
int x = read(), y = read();
addedge(x, ene(y)), addedge(y, ene(x));
}
bool fl = ;
for (int i=; i<=n; i++)
if (!vis[*i]&&!vis[*i-]){
cnt = ;
if (!dfs(*i-)){
while (cnt) vis[stk[cnt]] = , cnt--;
if (!dfs(*i)){
fl = ;
break;
}
}
}
if (fl){
for (int i=; i<=*n; i++)
if (vis[i]) printf("%d\n",i);
}else puts("NIE");
}
return ;
}
END
初涉2-SAT的更多相关文章
- 多边形碰撞 -- SAT方法
检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形 ...
- Struts2拦截器初涉
Struts2拦截器初涉 正在练习struts,本例是从一个pdf上摘抄的例子,那本pdf都不知道叫什么名字,不过感觉很适合初学者. 在这里要实现一个简单的拦截器"GreetingInter ...
- 初涉SQL Server性能问题(4/4):列出最耗资源的会话
在上3篇文章里,我们讨论了列出反映服务器当前状态的不同查询. 初涉SQL Server性能问题(1/4):服务器概况 初涉SQL Server性能问题(2/4):列出等待资源的会话 初涉SQL Ser ...
- 初涉SQL Server性能问题(3/4):列出阻塞的会话
在 初涉SQL Server性能问题(2/4)里,我们讨论了列出等待资源或正运行的会话脚本.这篇文章我们会看看如何列出包含具体信息的话阻塞会话清单. /************************ ...
- 初涉SQL Server性能问题(2/4):列出等待资源的会话
在初涉SQL Server性能问题(1/4)里,我们知道了如何快速检查服务器实例上正运行的任务数和IO等待的任务数.这个是轻量级的脚本,不会给服务器造成任何压力,即使服务器在高负荷下,也可以正常获得结 ...
- 【AS3 Coder】任务七:初涉PureMVC——天气预报功能实现
转自:http://www.iamsevent.com/post/36.html AS3 Coder]任务七:初涉PureMVC——天气预报功能实现 使用框架:AS3任务描述:了解PureMVC框架使 ...
- 初涉JavaScript模式系列 阶段总结及规划
总结 不知不觉写初涉JavaScript模式系列已经半个月了,没想到把一个个小点进行放大,竟然可以发现这么多东西. 期间生怕对JS的理解不到位而误导各位,读了很多书(个人感觉JS是最难的oo语言),也 ...
- POJ 3678 Katu Puzzle(2 - SAT) - from lanshui_Yang
Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a ...
- 初涉IPC,了解AIDL的工作原理及使用方法
初涉IPC,了解AIDL的工作原理及使用方法 今天来讲讲AIDL,这个神秘的AIDL,也是最近在学习的,看了某课大神的讲解写下的blog,希望结合自己的看法给各位同价通俗易懂的讲解 官方文档:http ...
- Map Labeler POJ - 2296(2 - sat 具体关系建边)
题意: 给出n个点 让求这n个点所能建成的正方形的最大边长,要求不覆盖,且这n个点在正方形上或下边的中点位置 解析: 当然是二分,但建图就有点还行..比较难想..行吧...我太垃圾... 2 - s ...
随机推荐
- react native 获取地图需要的SHA1
1.从电脑的根目录进入.android文件 2.进入.android文件后输入 keytool -v -list -keystore debug.keystore 3.回车输入密码,(可以直接回车不用 ...
- 码云最火爆开源项目 TOP 50,你都用过哪些?
前 20 名预览 排名软件排名软件 1zheng11AOSuite 2JFinal12Spiderman 3t-io13AG-Admin 4guns14renren-security 5hutool1 ...
- 黑马tomact学习一 tomcat下载 安装和卸载
- 超简单 Promise封装小程序ajax 超好用 以及封装登录
//网络类 //封装网络请求 const ajax = (ajaxData, method) => { wx.showLoading({ title: '加载中', mask: true }); ...
- .Net Core应用框架Util介绍(二) 转
Util的开源地址 https://github.com/dotnetcore/util Util的开源协议 Util以MIT协议开源,这是目前最宽松的开源协议,你不仅可以用于商业项目,还能把Util ...
- Jasper_table_resolve multiple copies of table in detail band issue
resolve method: (1) put table component into the Title band / Page Header band / Summary band, not i ...
- C#中MessageBox用法大全(附效果图)<转>
我们在程序中经常会用到MessageBox. MessageBox.Show()共有21中重载方法.现将其常见用法总结如下: 1.MessageBox.Show("Hello~~~~&quo ...
- Ionic之$scope 依赖注入报错
在开发Ionic过程中,发现会报在 LoginController 中引用locals报错,具体报错问题: ionic.bundle.js:19526 Error: [$injector:unpr] ...
- PaaS基础学习(1)
PaaS基础学习(1) PaaS学习笔记目录 PaaS基础学习(1) 在PaaS上开发Web.移动应用(2) PaaS优点与限制(3) 1. 基础单元,一个基础单元就是所研究实体的最小的不可分割的单元 ...
- cnblog之初来乍到
hello,大家好,我是蓝斯老师 一枚致力于android开发的攻城狮 很荣幸能够在博客园开博(博主以前是混CSDN的,原博客地址http://blog.csdn.net/lancees) 希望将来能 ...