几个关于2-sat的题

Posted buerdepepeqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了几个关于2-sat的题相关的知识,希望对你有一定的参考价值。

几个关于2-sat的题

 

HDU3062

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3062

题意:

从2n个人去宴会,有 m条关系 i和j不能同时去 夫妻不能同时去 问能否有n个人出席

题解:

因为是n对夫妻,我们将编号扩展 奇数是丈夫,偶数是妻子

那么m条关系就是 i*2+a 和j*2+b不能同时出席

建边 选b必选 a‘

选a必选b‘

然后判断是否在一个强连通分量里面即可

 

代码:

/**
*        ┏┓    ┏┓
*        ┏┛┗━━━━━━━┛┗━━━┓
*        ┃       ┃  
*        ┃   ━    ┃
*        ┃ >   < ┃
*        ┃       ┃
*        ┃... ⌒ ...  ┃
*        ┃       ┃
*        ┗━┓   ┏━┛
*          ┃   ┃ Code is far away from bug with the animal protecting          
*          ┃   ┃   神兽保佑,代码无bug
*          ┃   ┃           
*          ┃   ┃       
*          ┃   ┃
*          ┃   ┃           
*          ┃   ┗━━━┓
*          ┃       ┣┓
*          ┃       ┏┛
*          ┗┓┓┏━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
//                           _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                           O\ = /O
//                       ____/`---‘\____
//                     .‘ \|     |// `.
//                     / \||| : |||// \
//                   / _||||| -:- |||||- \
//                   |   | \ - /// |   |
//                   | \_| ‘‘\---/‘‘ |   |
//                   \ .-\__ `-` ___/-. /
//                 ___`. .‘ /--.--\ `. . __
//               ."" ‘< `.___\_<|>_/___.‘ >‘"".
//             | | : `- \`.;`\ _ /`;.`/ - ` : | |
//             \ \ `-.   \_ __\ /__ _/   .-` / /
//         ======`-.____`-.___\_____/___.-`____.-‘======
//                           `=---=‘
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                     佛祖保佑     永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 2e3 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b)
   return b ? gcd(b, a % b) : a;

LL lcm(LL a, LL b)
   return a / gcd(a, b) * b;

double dpow(double a, LL b)
   double ans = 1.0;
   while(b)
       if(b % 2)ans = ans * a;
       a = a * a;
       b /= 2;
  return ans;

LL quick_pow(LL x, LL y)
   LL ans = 1;
   while(y)
       if(y & 1)
           ans = ans * x % mod;
      x = x * x % mod;
       y >>= 1;
  return ans;

struct EDGE
   int v, nxt;
edge[maxn * maxn];
int n, m;
int head[maxn], tot;
void add_edge(int u, int v)
   edge[tot].v = v;
   edge[tot].nxt = head[u];
   head[u] = tot++;

int low[maxn], dfn[maxn], num, in[maxn], scc[maxn];
int Stack[maxn], top, cnt;
void tarjan(int u)
   low[u] = dfn[u] = ++num;
   Stack[top++] = u;
   in[u] = 1;
   for(int i = head[u]; i != -1; i = edge[i].nxt)
       int v = edge[i].v;
       if(!dfn[v])
           tarjan(v);
           low[u] = min(low[u], low[v]);
      else if(in[v])
           low[u] = min(low[u], dfn[v]);
     
 
   if(low[u] == dfn[u])
       int v;
       cnt++;
       do
           v = Stack[--top];
           in[v] = 0;
           scc[v] = cnt;
      while(u != v);
 

bool Two_sat()
   for(int i = 0; i < 2 * n; i++)
       if(!dfn[i])
           tarjan(i);
     
 
   for(int i = 0; i < n; i++)
       if(scc[i * 2] == scc[i * 2 + 1]) return false;
 
   return true;

int main()
#ifndef ONLINE_JUDGE
   FIN
#endif
   while(~scanf("%d%d", &n, &m))
       memset(head, -1, sizeof(head));
       memset(dfn, 0, sizeof(dfn));
       memset(low, 0, sizeof(low));
       memset(scc, 0, sizeof(scc));
       tot = 0;
       num = 0;
       top = 0;
       cnt = 0;
       for(int i = 1; i <= m; i++)
           int a, vala;
           int b, valb;
           scanf("%d%d%d%d", &a, &b,  &vala, &valb);
           a = a * 2 + vala;
           b = b * 2 + valb;
           add_edge(a, b ^ 1);  //选A必选B‘
           add_edge(b, a ^ 1);  //选B必选A‘
     
       if(Two_sat())
           printf("YES\n");
?
      else
           printf("NO\n");
     
 
   return 0;

洛谷P4782

传送门:https://www.luogu.org/problem/P4782

题意:

2-sat模板题

题解:

建边

为或为?

?

建图

代码:

/**
*        ┏┓    ┏┓
*        ┏┛┗━━━━━━━┛┗━━━┓
*        ┃       ┃  
*        ┃   ━    ┃
*        ┃ >   < ┃
*        ┃       ┃
*        ┃... ⌒ ...  ┃
*        ┃       ┃
*        ┗━┓   ┏━┛
*          ┃   ┃ Code is far away from bug with the animal protecting          
*          ┃   ┃   神兽保佑,代码无bug
*          ┃   ┃           
*          ┃   ┃       
*          ┃   ┃
*          ┃   ┃           
*          ┃   ┗━━━┓
*          ┃       ┣┓
*          ┃       ┏┛
*          ┗┓┓┏━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
//                           _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                           O\ = /O
//                       ____/`---‘\____
//                     .‘ \|     |// `.
//                     / \||| : |||// \
//                   / _||||| -:- |||||- \
//                   |   | \ - /// |   |
//                   | \_| ‘‘\---/‘‘ |   |
//                   \ .-\__ `-` ___/-. /
//                 ___`. .‘ /--.--\ `. . __
//               ."" ‘< `.___\_<|>_/___.‘ >‘"".
//             | | : `- \`.;`\ _ /`;.`/ - ` : | |
//             \ \ `-.   \_ __\ /__ _/   .-` / /
//         ======`-.____`-.___\_____/___.-`____.-‘======
//                           `=---=‘
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                     佛祖保佑     永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 2e6 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b)
   return b ? gcd(b, a % b) : a;

LL lcm(LL a, LL b)
   return a / gcd(a, b) * b;

double dpow(double a, LL b)
   double ans = 1.0;
   while(b)
       if(b % 2)ans = ans * a;
       a = a * a;
       b /= 2;
  return ans;

LL quick_pow(LL x, LL y)
   LL ans = 1;
   while(y)
       if(y & 1)
           ans = ans * x % mod;
      x = x * x % mod;
       y >>= 1;
  return ans;

struct EDGE
   int v, nxt;
edge[maxn << 1];
   int n, m;
int head[maxn], tot;
void add_edge(int u, int v)
   edge[tot].v = v;
   edge[tot].nxt = head[u];
   head[u] = tot++;

int low[maxn], dfn[maxn], num,in[maxn],scc[maxn];
int Stack[maxn],top, cnt;
void tarjan(int u)
   low[u] = dfn[u] = ++num;
   Stack[top++] = u;
   in[u] = 1;
   for(int i = head[u]; i != -1; i = edge[i].nxt)
       int v = edge[i].v;
       if(!dfn[v])
           tarjan(v);
           low[u] = min(low[u], low[v]);
      else if(in[v])
           low[u] = min(low[u], dfn[v]);
     
 
   if(low[u] == dfn[u])
       int v;
       cnt++;
       do
           v = Stack[--top];
           in[v] = 0;
           scc[v] = cnt;
      while(u != v);
 

bool Two_sat()
   for(int i = 1; i <= 2 * n; i++)
       if(!dfn[i])
           tarjan(i);
     
 
   for(int i = 1; i <= n; i++)
       if(scc[i] == scc[i + n]) return false;
 
   return true;

int main()
#ifndef ONLINE_JUDGE
   FIN
#endif
   memset(head, -1, sizeof(head));
   tot = 0;
?
   scanf("%d%d", &n, &m);
   for(int i = 1; i <= m; i++)
       int a, vala;
       int b, valb;
       scanf("%d%d%d%d", &a, &vala, &b, &valb);
       int nota = !vala;
       int notb = !valb;
       add_edge(a + nota * n, b + valb * n);
       add_edge(b + notb * n, a + vala * n);
 
   if(Two_sat())
       printf("POSSIBLE\n");
       for(int i = 1; i <= n; i++)
           printf("%d ", scc[i] > scc[i + n]);
     
  else
       printf("IMPOSSIBLE\n");
 
   return 0;

 

以上是关于几个关于2-sat的题的主要内容,如果未能解决你的问题,请参考以下文章

真真假假分不清——浅谈 2-SAT

2-SAT学习整理

关于矩阵的题

2-SAT

关于类加载顺序问题的题

170907-关于JavaWeb的题