算法复习——2—sat(bzoj2199)

题目:

Description

由于对Farmer John的领导感到极其不悦,奶牛们退出了农场,组建了奶牛议会。议会以“每头牛 都可以获得自己想要的”为原则,建立了下面的投票系统: M只到场的奶牛 (1 <= M <= 4000) 会给N个议案投票(1 <= N <= 1,000) 。每只 奶牛会对恰好两个议案 B_i and C_i (1 <= B_i <= N; 1 <= C_i <= N)投 出“是”或“否”(输入文件中的‘Y‘和‘N‘)。他们的投票结果分别为VB_i (VB_i in {‘Y‘, ‘N‘}) and VC_i (VC_i in {‘Y‘, ‘N‘})。 最后,议案会以如下的方式决定:每只奶牛投出的两票中至少有一票和最终结果相符合。 例如Bessie给议案1投了赞成‘Y‘,给议案2投了反对‘N‘,那么在任何合法的议案通过 方案中,必须满足议案1必须是‘Y‘或者议案2必须是‘N‘(或者同时满足)。 给出每只奶牛的投票,你的工作是确定哪些议案可以通过,哪些不能。如果不存在这样一个方案, 输出"IMPOSSIBLE"。如果至少有一个解,输出: Y 如果在每个解中,这个议案都必须通过 N 如果在每个解中,这个议案都必须驳回 ? 如果有的解这个议案可以通过,有的解中这个议案会被驳回 考虑如下的投票集合: - - - - - 议案 - - - - - 1 2 3 奶牛 1 YES NO 奶牛 2 NO NO 奶牛 3 YES YES 奶牛 4 YES YES 下面是两个可能的解: * 议案 1 通过(满足奶牛1,3,4) * 议案 2 驳回(满足奶牛2) * 议案 3 可以通过也可以驳回(这就是有两个解的原因) 事实上,上面的问题也只有两个解。所以,输出的答案如下: YN?

Input

* 第1行:两个空格隔开的整数:N和M * 第2到M+1行:第i+1行描述第i只奶牛的投票方案:B_i, VB_i, C_i, VC_i

Output

* 第1行:一个含有N个字符的串,第i个字符要么是‘Y‘(第i个议案必须通过),或者是‘N‘ (第i个议案必须驳回),或者是‘?‘。 如果无解,输出"IMPOSSIBLE"。

Sample Input

3 4

1 Y 2 N

1 N 2 N

1 Y 3 Y

1 Y 2 Y

Sample Output

YN?

HINT

Source

Gold

题解:

2-sat问题的模板题目,先说2-sat问题的基本解法:

一些问题可以转成布尔方程来求解····

我们的目的是将其布尔方程的每个文字拆开成两点,一点表示其本身,一点表示它的非,比如a就拆成a与┐a,并且将各种运算符号转化为只含有^(与)和->(A->B表示A为真则B为真)的形式,比如∨转化为┐a -> b ^ ┐b -> a  ,a一定为真就转换为  ┐a->a  的形式,然后将->转换成边,两边连上对应的点。

如果a与┐a在最后建成的图的同一个强连通分量里···那么布尔方程有解

如果a所在强连通分量的拓扑序在┐a所在强连通分量的拓扑序之后,那么a为真,之前a为假,如果相等则真假均可以取。这里求拓扑序直接用tarjian即可,先找到的强连通分量的拓扑序一定更大

以上就是基本知识

但这道题有点特殊·····因为包含a拓扑序与┐a相等的情况要判断····用tarjian的话有点麻烦···

但n很小···直接dfs即可····若a可以到达┐a,则说明a可能与┐a在同一强连通分量或者a所在强连通分量的拓扑序小于等于┐a的拓扑序

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=2005;
const int M=10005;
int first[N],next[M],go[M],tot=1,n,m;
bool visit[N];
inline void comb(int a,int b)
{
  next[++tot]=first[a],first[a]=tot,go[tot]=b;
}
inline int tran(int a)
{
  return (a%2==1)?a+1:a-1;
}
inline int R()
{
  char c;
  int f=0;
  for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
  for(;c<=‘9‘&&c>=‘0‘;c=getchar())
    f=(f<<3)+(f<<1)+c-‘0‘;
  return f;
}
inline void dfs(int u)
{
  visit[u]=true;
  for(int e=first[u];e;e=next[e])
  {
    if(!visit[go[e]])
      dfs(go[e]);
  }
}
inline bool jud(int u)
{
  memset(visit,false,sizeof(visit));
  dfs(u);
  if(!visit[tran(u)])  return true;
  else return false;
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R(),m=R();
  char s[5],t[5];
  int a,b;
  for(int i=1;i<=m;i++)
  {
    scanf("%d%s%d%s",&a,s,&b,t);
    int t1,t2;
    if(s[0]==‘Y‘)
      t1=a*2-1;
    else
      t1=a*2;
    if(t[0]==‘Y‘)
      t2=b*2-1;
    else
      t2=b*2;
    comb(tran(t2),t1);
    comb(tran(t1),t2);
  }
  for(int i=1;i<=n;i++)
  {
    bool flag1=jud(i*2-1);
    bool flag2=jud(i*2);
    if(!flag1&&!flag2)  {cout<<"IMPOSSIBLE"<<endl;return 0;}
    else if(!flag1)  cout<<"N";
    else if(!flag2)  cout<<"Y";
    else cout<<"?";
  }
  return 0;
}
时间: 2024-10-05 12:04:40

算法复习——2—sat(bzoj2199)的相关文章

C语言排序算法复习

排序算法有很多种,这里在复习和分析的基础上,做一个自己的总结: 首先要知道有哪些排序算法,google一下,有云C语言7大经典排序算法(也有8大).主要包括冒泡排序,快速排序,选择排序,插入排序,希尔排序,归并排序,堆排序,8大的还有基数排序.各有各的版本,代码写法也各不相同.所以这里以整理思路为先,代码只是作为自己的一个备份. 搞清楚的概念:稳定排序和不稳定排序,就看序列中两个值相等的数,排完序之后的相对位置是否改变,如果改变了就不稳定. 内部排序和外部排序,只用到内存即可完成排序的就叫内部排

排序算法复习

排序算法复习 作者:vpoet mails:[email protected] 注:转载请注明出处 #include <iostream> #include <windows.h> using namespace std; void Bubble_Sort(int UnSort[],int length); void Select_Sort(int UnSort[],int length); void Insert_Sort(int UnSort[],int length); vo

算法复习计划

写在前面 随着四月的到来, 离省选越来越近了. 从NOIP到现在, 学到了很多很多东西, 有的学的比较深入, 有的只是略知一二 从明天开始, 进行针对省选的算法复习计划. 省选前完成. 重点是对算法的理解和应用, 还会注重模板习惯的养成 计划内容 1. 数据结构 一直觉得我数据结构学的还可以, 不过列出来发现会的也没多少. 少就少吧, 省选够用就行... 线段树 树状数组 并查集 哈希表 STL treap splay 树链剖分 主席树(可忽略) 字符串(KMP, 后缀数组) 2. 图论 掌握经

算法复习-研一上

算法复习  包含主题: 贪心算法 , 分治法,动态规划,回溯法,分支限界,线性规划 关键词:最优子结构 Q:贪心与动态规划中间的联系和区别 p93 后面总结 (背部问题,0-1背包问题) 递归分治算法 基本思想:将一个大的问题分成若干小的子问题问题,分而治之 一般步骤:1.分解将原问题分为若干规模小,相互独立与原问题形式相同的问题   2.求解,求解各个子问题,当问题被划分的足够小的时候,就能很容易求解     3.合并,将子问题逐层合并,得到最后的解 经典问题 二分搜索: 合并排序(将想要排序

数据结构与算法复习(一) 排序算法(I)

这篇文章将会介绍最常见的排序算法(使用 JavaScript 语言实现) PS:这里我会尽量使用语言无关的语法去写,大家不要太在意语言,重要的是算法的实现思路 1.冒泡排序 将数组分为有序区(左边)和无序区(右边) 每次从无序区的最后一个元素开始,一直向前冒泡到无序区的第一个位置,使其变成有序 function swap(A, i, j) { if (i === j) return [A[i], A[j]] = [A[j], A[i]] } function bubbleSort(A) { fo

数据结构与算法复习

数据结构回顾与整理 复习资料<数据结构与算法 Javascript描述> 人民邮电出版社 数据结构与算法学的次数再多也不为过. 1,数组array:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,来计算元素之间存储位置的偏移量. 除了常用的方法,ES5中新增加了几个迭代方法,forEach(),every()some(),reduce(),map(),filter(). 2.列表list:是一组有序数据.其中的数据项被称为 元素.包含属性/方法有listsize,pos(当

算法复习(1)——并查集

翻翻我做过的286道题,发现忘了好多不记得啥了  呵呵呵.... 于是毅然决定老师让好好复习复习.. 第一节---并查集 1.what is 并查集?? 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其 间要反复查找一个元素在哪个集合中.这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往 在空间上过大,计算机无法承受:即使在空间上勉

算法复习——拓展欧几里得(poj1061)

题目: Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 

通过“回文字算法”复习C++语言。

一.什么是回文字 给定一个字符串,从前往后读和从后往前读,字符串序列不变.例如,河北省农村信用社的客服电话是“96369”,无论从后往前读,还是从前后往后读,各个字符出现的位置不变. 二.功能实现 (一).给定一个字符串,判断该字符串是否是回文字. (二).给定一个任意字符串,判断是否可以转换为回文字,如果可以转换为回文字,给出具体的算法. 三.C++语言实现版本(JAVA语言版本后续实现) (一)头文件 (BackText.h) /* * BackText.h * * Created on: