http://cogs.pro:8080/cogs/problem/problem.php?pid=pyzQimjkj

题意:有n个集合,每个集合有俩元素,要从n个中各选一个放一堆,但是有的俩不能同时取,让你找出一种选取方案。

思路:2-SAT板子,主要学一下这个算法。算法流程:

构图:若a,b不能同时选,连a->b'和b->a'

求图的极大强连通子图:直接tarjan。

缩点然后变成个新的DAG:因为一个强连通分量里选一个其他都要选,一个不选其他都不能选,所以直接缩成一个点。

对新图拓排:要存反边,这个一开始不造为啥,后来看解释是因为传递的是不选择标记,这边往前代走,对面那边往后代走(对这个起作用)。。选一个他后代都得选,不选谁谁的前代都不能选,so...

自底向上进行选择,删除。

输出。

#include<bits/stdc++.h>
#define oth(x) x&1?x+1:x-1
using namespace std;
const int N = 20010; struct Edge{
int to,nxt;
}e[50010];
int head[N],dfn[N],low[N],st[N],bel[N];
bool vis[N];
int ru[N],q[N],opp[N],pr[N];
int tot_edge,n,nn,m,tot_node,top,cnt_block,L,R;
vector<int>mp[N]; inline int read() {
int x = 0,f = 1;char ch = getchar();
for (; ch<'0'||ch>'9'; ch=getchar()) if(ch=='-') f=-1;
for (; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
return x * f;
}
void add_edge(int u,int v){
e[++tot_edge].to = v;
e[tot_edge].nxt = head[u];
head[u] = tot_edge;
}
void tarjan(int u){
dfn[u] = low[u] = ++tot_node;
st[++top] = u;
vis[u] = true;
for(int i=head[u];i;i=e[i].nxt){
int v = e[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[v],low[u]);
}
else if(vis[v])
low[u] = min(dfn[v],low[u]);
}
if(low[u]==dfn[u]){
++cnt_block;
do{
vis[st[top]] = false;
bel[st[top]] = cnt_block;
top--;
}while(st[top+1]!=u);
}
}
void topsort(){
L=1;R=0;
for(int i=1;i<=cnt_block;i++){
if(ru[i]==0) q[++R] = i;
}
while(L<=R){
int u = q[L++];
if(pr[u]) continue;
pr[u] = 1;pr[opp[u]] = 2;
int sz = mp[u].size();
for(int i=0;i<sz;i++){
int v = mp[u][i];
ru[v]--;
if(ru[v]==0) q[++R] = v;
}
}
}
bool work(){
for(int i=1;i<=nn;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=nn;i++){
if(bel[i]==bel[oth(i)]) return false;
opp[bel[i]] = bel[oth(i)];
opp[bel[oth(i)]] = bel[i];
}
for(int u=1;u<=nn;u++){
for(int i=head[u];i;i=e[i].nxt){
int v = e[i].to;
if(bel[u]!=bel[v]){
ru[bel[u]]++;
mp[bel[v]].push_back(bel[u]);
}
}
}
topsort();
return true;
}
int main(){
freopen("spo.in","r",stdin);
freopen("spo.out","w",stdout);
n = read(),m = read(),nn = n<<1;
for(int i=1;i<=m;i++){
int a = read(),b = read();
add_edge(a,oth(b));
add_edge(b,oth(a));
}
if(work()){
for(int i=1;i<=nn;i++){
if(pr[bel[i]]==1) cout<<i<<endl;
}
}
else puts("NIE");
return 0;
}

最新文章

  1. EF:The provider did not return a ProviderManifest instance
  2. handlebars.js 用 &lt;br&gt;替换掉 内容的换行符
  3. 深入grootJs(进阶教程)
  4. lazyload.js实现图片异步载入
  5. BPMN流程图的绘制的注意要点
  6. HTML5 Web Storage -- 让Cookies看起来如此古老
  7. POJ 1719 二分图最大匹配(记录路径)
  8. C++中各种容器的类型与特点
  9. Qt3D教程
  10. java学习之网络编程之echo程序
  11. java中的String类常量池详解
  12. 2.4 easyui - panel的使用
  13. DllRegisterServer的调用失败的问题解决方法
  14. ELK学习总结(2-4)bulk 批量操作-实现多个文档的创建、索引、更新和删除
  15. T410升级笔记
  16. 玩转spring mvc(六)---自定义异常跳转页面
  17. Timeline高级扩展
  18. Perl IO:操作系统层次的IO
  19. properties中的编码如何生成:例如\u7AD9\u70B9这种。
  20. PAT L2-022 重排链表

热门文章

  1. vue 初始化table数据,数据闪现的问题
  2. JAVA对象实例化方式总结
  3. Python中的inf与nan
  4. ArrayList源码分析--jdk1.8
  5. Micropython TPYBoard v102 温湿度短信通知器(基于SIM900A模块)
  6. 【Java笔记】【Java核心技术卷1】chapter3 D5运算符
  7. Activiti6系列(3)- 快速体验
  8. Java高级面试题解析(二):百度Java面试题前200页(精选)
  9. Mybatis学习笔记之---环境搭建与入门
  10. 《深入理解Java虚拟机》-Java代码是如何运行的