• HDU 1824 简单2-sat


     1 /*
     2 HDU - 1824
     3 主要是题目描述比较坑爹,注意:队长回家两队员都必须在,只要有一个队员回家,队长都必须在。
     4 同时贴上一段看到的让我警醒的话:
     5 “这里我说一个细节问题,很多初学者容易忽视
     6 那就是边的链接方向。
     7 到底是谁指向谁,这个问题,很多初学者容易混淆(比如本人。。)
     8 其实问题的关键是考虑,额。。就用这个题来说吧。
     9 关键是考虑,一个矛盾关系对里面,到底是两个人是能同时出现,还是能同时不出现
    10 这个题里面,队长和队员,是两者可以同时出现的。但是两者却不能同时离开
    11 而后面给的关系里面,是指两个人可以同时走,但是却不能同时都在”
    12 2—sat 理解拆对象拆分成两个点(T,F)
    13 建立好点之间的连通关系
    14 我没将队员看成一点,而是每个人作为一个对象
    15 */#include <stdio.h>
    16 #include <stdlib.h>
    17 #include <string.h>
    18 #include <math.h>
    19 #include <ctype.h>
    20 #include <string>
    21 #include <iostream>
    22 #include <sstream>
    23 #include <vector>
    24 #include <queue>
    25 #include <stack>
    26 #include <map>
    27 #include <list>
    28 #include <set>
    29 #include <algorithm>
    30 #define INF 0x3f3f3f3f
    31 #define LL long long
    32 #define eps 1e-7
    33 #define maxn 3100
    34 using namespace std;struct TwoSAT{    int n;
    35     vector<int> G[maxn*2];//注意点集的大小
    36     bool mark[maxn*2];//联系《2-sat算法解析》中的红蓝标色,夫妻不能被标同一种颜色;因为仇人间没有连边,所以在图本身,不可能将两人标同一个颜色
    37     int S[maxn*2],c;//存储当前被标记的点,可用于标记的回退
    38     bool dfs(int x)
    39     {        if (mark[x^1]) return false;//真假同时被标记,逻辑矛盾
    40         if (mark[x]) return true;//x被标记,意味着下面的节点也被标记,思想是记忆化搜索
    41         mark[x]=true;
    42         S[c++]=x;        for(int i=0;i<G[x].size();i++)            if(!dfs(G[x][i])) return false;//同一个强联通分量应该表上同一种颜色
    43         return true;
    44     }
    45     void init(int n)
    46     {        this->n=n;        for(int i=0;i<n*2;i++) G[i].clear();
    47         memset(mark,0,sizeof(mark));
    48     }
    49     void add_edge(int u,int v)//这个地方灵活多变一点
    50     {
    51         G[u].push_back(v);//        cout<<u<<"->"<<v<<endl;
    52     }    void addT(int a,int b,int c)
    53     {
    54         add_edge(2*a+1,2*b);
    55         add_edge(2*a+1,2*c);
    56         add_edge(2*b+1,2*a);//        add_edge(2*b,2*c);
    57         add_edge(2*c+1,2*a);//        add_edge(2*c+1,2*b+1);
    58     }    bool solve()
    59     {        for(int i=0;i<n*2;i+=2)
    60         {            if(!mark[i] && !mark[i^1])//真假都没被标记才需dfs,思考一下,原书上写的是[mark+1],这是由i的取值和步长决定的,这里更改,使逻辑含义统一
    61             {
    62                 c=0;//记得清零
    63                 if(!dfs(i))//将i标记为true
    64                 {                    while(c>0) mark[S[--c]]=false;                    if (!dfs(i^1)) return false;//更改初始标号颜色。只要有一个对象不能“二选一”,则2-sat无解
    65                 }
    66             }
    67         }        return true;
    68     }
    69 }sat;//每个人都有一个编号x
    70 //2x表示留下,2x+1表示回家
    71 int T,M;int nextint()
    72 {    int x;
    73     scanf("%d",&x);    return x;
    74 }int main()
    75 {    while(cin>>T>>M)
    76     {
    77         sat.init(T*3+1);        for(int i=0;i<T;i++)
    78         {            int a,b,c;
    79             a=nextint();b=nextint();c=nextint();//            cin>>a>>b>>c;
    80             sat.addT(a,b,c);
    81         }        for(int i=0;i<M;i++)
    82         {            int x,y;
    83             x=nextint();y=nextint();//            cin>>x>>y;
    84             sat.add_edge(2*x,2*y+1);
    85             sat.add_edge(2*y,2*x+1);
    86         }        if (sat.solve()) cout<<"yes"<<endl;else cout<<"no"<<endl;
    87     }    return 0;
    88 }
  • 相关阅读:
    Spring Boot中使用logback日志框架
    Java日志框架-logback配置文件参考(转)
    Java日志框架-logback配置文件多环境日志配置(开发、测试、生产)(原始解决方法)
    MySQL取每组的前N条记录
    跟大佬一起读源码:CurrentHashMap的扩容机制
    源码速读及点睛:HashMap
    求两个Linux文本文件的交集、差集、并集
    哪个先执行:@PostConstruct和@Bean的initMethod?
    Android Studio3.0 Error:Execution failed for task ':app:javaPreCompileDebug' 错误
    Android原生项目集成React Native
  • 原文地址:https://www.cnblogs.com/little-w/p/3581504.html
Copyright © 2020-2023  润新知