zoukankan      html  css  js  c++  java
  • poj3207 2-SAT入门

    一开始题意没读懂 = =

    题意:比如说对于表盘上a到b、c到d都要连边,这两个边不能交叉。这两个边要么都在圆内要么都在圆外,而且可以是曲线= =

    比如这种情况:(Reference:http://blog.csdn.net/l04205613/article/details/6668318)

    (左边情况看似是合法的,但是一个边在圆内一个在圆外,形成矛盾了)

    这回只需判断是否可行不用输出方案,这样就简单多了

    STEP:构图,矛盾的地方连边->tarjan求scc->判断是否a和not a在同一分量内

      1 #include "iostream"
      2 #include "cstring"
      3 #include "stack"
      4 using namespace std;
      5 #define maxn 2010
      6 
      7 int G[maxn][maxn],dx[maxn],dy[maxn];
      8 int pre[maxn],lowlink[maxn],sccno[maxn];
      9 int dfs_clock,scc_cnt,N,M;
     10 stack<int> St;
     11 
     12 void tarjan(int u)
     13 {
     14     pre[u]=lowlink[u]=++dfs_clock;
     15     St.push(u);
     16     for (int i=1;i<=G[u][0];i++)
     17     {
     18         int v=G[u][i];
     19         if (!pre[v])
     20         {
     21             tarjan(v);
     22             lowlink[u]=min(lowlink[u],lowlink[v]);
     23         }
     24         else if (!sccno[v])
     25         {
     26             lowlink[u]=min(lowlink[u],pre[v]);
     27         }
     28     }
     29     if (lowlink[u]==pre[u])
     30     {
     31         scc_cnt++;
     32         for (;;)
     33         {
     34             int x=St.top();
     35             St.pop();
     36             sccno[x]=scc_cnt;
     37             if (x==u) break;
     38         }
     39     }
     40 }
     41 
     42 void find_scc(int n)
     43 {
     44     dfs_clock=scc_cnt=0;
     45     memset(sccno,0,sizeof(sccno));
     46     memset(pre,0,sizeof(pre));
     47     for (int i=1;i<=n;i++)
     48         if (!pre[i])
     49             tarjan(i);
     50 }
     51 
     52 void add_edge(int x,int y)
     53 {
     54     G[x][0]++;
     55     G[x][G[x][0]]=y;
     56 }
     57 
     58 int main()
     59 {
     60     cin>>N>>M;
     61     for (int i=1;i<=M;i++)
     62         cin>>dx[i]>>dy[i];
     63 
     64     //1->N:dx[i]->dy[i]走圆内
     65     //N+1->2*N:dx[i]->dy[i]走圆外
     66     for (int i=1;i<=N;i++)
     67     {
     68         for (int j=i+1;j<=N;j++)
     69         {
     70             if ((dx[j]<dx[i])&&(dx[i]<dy[j])&&(dy[j]<dy[i]))
     71             {
     72                 add_edge(i,j+N);
     73                 add_edge(j+N,i);
     74                 add_edge(j,i+N);
     75                 add_edge(i+N,j);
     76             }
     77             if ((dx[i]<dx[j])&&(dx[j]<dy[i])&&(dy[i]<dy[j]))
     78             {
     79                 add_edge(i,j+N);
     80                 add_edge(j+N,i);
     81                 add_edge(j,i+N);
     82                 add_edge(i+N,j);
     83             }
     84         }
     85     }
     86 
     87     find_scc(2*N);
     88 
     89     for (int i=1;i<=N;i++)
     90     {
     91         if (sccno[i]==sccno[i+N])
     92         {
     93             cout<<"the evil panda is lying again"<<endl;
     94             return 0;
     95         }
     96     }
     97     cout<<"panda is telling the truth..."<<endl;
     98     return 0;
     99 
    100 }
    View Code

    ------------------------------------------------------------------------------------------------

    注意:对于2-SAT问题构图的时候有些题还要纠结一下是连单向边(如poj3678)还是双向边(如本题),

    reference:http://blog.csdn.net/u011026968/article/details/10823853

    本题中,我们以第二个判断条件if ((dx[i]<dx[j])&&(dx[j]<dy[i])&&(dy[i]<dy[j]))为例:

    若j在圆内,那么i一定在圆外

    若j在圆外,那么i一定在圆内

    若i在圆内,那么j一定在圆外

    若i在圆外,那么j一定在圆内

    注意蓝色部分就是双向边了

    ------------------------------------

    而poj 3683题中:

    我们以构图时的第一个判断条件if (min(S[i]+D[i],S[j]+D[j])>max(S[i],S[j]))为例,

    若i在前段举行,那么j一定在后半段举行

    若j在后半段举行,那么i不一定要在前半段举行

    若j在前段举行,那么i一定在后半段举行

    若i在后半段举行,那么j不一定要在前半段举行

    注意红色部分:因为不确定(本判断条件中并没有讨论后半段的时间),所以不能双向边

  • 相关阅读:
    kuberdm安装
    docker网络
    docker安装及基本使用
    慢日志
    mysql-5.7主从复制
    MySQL-5.6主从复制
    MySQL索引原理
    Kubernetes的kubeadm项目安装部署
    十六、kubernetes之安全实验案例
    十五、Kubernetes之安全配置
  • 原文地址:https://www.cnblogs.com/pdev/p/4060698.html
Copyright © 2011-2022 走看看