题意

给定一个有向图,问是否能够分成两个有向完全图。

思路

裸的2-sat……我们设一个完全图为0,另一个完全图为1,对于一个点对(u, v),如果u、v不是双向连通则它们两个不能在一组,即u和v至少又一个为0,至少又一个为1。则我们向2-sat中加条u->v', u'->v, v->u', u'->v的边,然后验证可行性即可。

(关于2-SAT的建图可以见这篇题解

代码

[cpp]
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, end) for (int i = begin; i <= end; i ++)
using namespace std;

const int MAXN = 2005;
const int MAXE = MAXN * MAXN;
bool map[105][105];
struct node{
int u, v;
int next;
}arc[MAXE];
int cnt, head[MAXN];
void init(){
cnt = 0;
MEM(head, -1);
return ;
}
void insert(int u, int v){
arc[cnt].u = u;
arc[cnt].v = v;
arc[cnt].next = head[u];
head[u] = cnt ++;
}
/* ---- Tarjan ---- */
int scc_num, scc[MAXN];
int dfn[MAXN], low[MAXN], id;
stack st;
bool vis[MAXN], instack[MAXN];
void dfs(int u){
vis[u] = instack[u] = 1;
st.push(u);
dfn[u] = low[u] = ++ id;
for (int i = head[u]; i != -1; i = arc[i].next){
int v = arc[i].v;
if (!vis[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v]){
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]){
++ scc_num;
while(st.top() != u){
scc[st.top()] = scc_num;
instack[st.top()] = 0;
st.pop();
}
scc[st.top()] = scc_num;
instack[st.top()] = 0;
st.pop();
}
return ;
}
void tarjan(int n){
MEM(vis, 0);
MEM(instack, 0);
MEM(dfn, 0);
MEM(low, 0);
MEM(scc, 0);
id = scc_num = 0;
while(!st.empty())
st.pop();

for (int i = 1; i <= n; i ++){ //枚举节点
if (!vis[i])
dfs(i);
}
return ;
}
/* ---- Tarjan ---- */
int opp[MAXN]; //与i同组的标号i', 默认设为i+N;
void set_opp(int N){ //设定同组标号.
for (int i = 1; i <= N; i ++)
opp[i] = i + N;
return ;
}
//根据y约束向构图中加边,N表示组数.
//(通常一组表示一个布尔变量的0\1值, 但也有题目表示的是一组互斥约束的布尔值)
void add_clause(int N){
init();
set_opp(N);
for (int i = 1; i <= N; i ++){
for (int j = 1; j <= N; j ++){
if (i == j || (map[i][j] && map[j][i])) continue;
insert(i, opp[j]);
insert(opp[i], j);
insert(j, opp[i]);
insert(opp[j], i);
}
}
return ;
}
bool check(int N){ //2-SAT判定.N表示组数.opp[i]表示与i同互斥组的另一个点
tarjan(2*N);
for (int i = 1; i <= 2*N; i ++){
if (scc[i] == scc[opp[i]]){
return false;
}
}
return true;
}
int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
int n;
while(scanf("%d", &n) != EOF){
MEM(map, 0);
for (int i = 1; i <= n; i ++){
int tmp;
while(scanf("%d", &tmp), tmp){
map[i][tmp] = 1;
}
}
add_clause(n);
if (check(n)){
puts("YES");
}
else{
puts("NO");
}

}
return 0;
}
[/cpp]

最新文章

  1. 微信H5中的一些坑
  2. nodejs redis 发布订阅机制封装
  3. php下载中文名文件
  4. Halcon与MFC交互编程
  5. 深入理解OOP(四): 多态和继承(抽象类)
  6. KMP算法学习
  7. 管道导致的while循环体变量失效
  8. iframe根据子页面自动调整大小
  9. kindeditor编辑器图片水印
  10. bzoj1295: [SCOI2009]最长距离
  11. Python(Django) 连接MySQL(Mac环境)
  12. Linux 释放cached内存
  13. 那些常用的eclipse快捷键
  14. SQL Server 基础 03 查询数据基础
  15. Python数据分析学习-re正则表达式模块
  16. ajax获取值的两种方法
  17. asp.net core mvc ajaxform submit files
  18. js高级---本地对象、内置对象、宿主对象
  19. _CSS Hack
  20. Linux shell脚本读取用户输入的参数

热门文章

  1. pandas的merge方法
  2. Oracle AWR 之 通过dbms_workload_repository.awr_report_text(html)函数在客户端生成AWR报告
  3. Find them, Catch them---poj1703(并查集)
  4. 002-线程实现方式【thread、runnable、callale、thread和runnable对比】
  5. Openstack(十五)快速添加新计算节点
  6. Java基础知识 Set
  7. Java基础教程:IO流与文件基础
  8. hdu1199 线段树
  9. 20155203 2016-2017-4 《Java程序设计》第8周学习总结
  10. Python: 字符串中嵌入变量