• 纠结死人的2-sat


    通用解法:

    对于2-sat,一般而言有两种做法。做法一:直接for一遍未被选过的节点。假定当前节点为Ai,dfs判定及选定它的后代节点。若不满足,则再对Ai'进行此操作。做法二:先tarjan缩点判是否矛盾。然后拓扑排序自底向上输出答案。

    关 于自底向上算法的证明我觉得论文说得不是很清楚,在这里提一下。自底向上操作时,因为是拓扑排序后的序列,所以当选到某个点时,它的出度必然为零。既然出 度为零,那么有三种可能:一是它没有后代节点,可以选;二是它的后代节点都被选完了,它可以选;第三种比较复杂,设当前节点未被遍历节点为Si,那么它没 被选择的后代节点设为v。有一种不满足题意的情况是,选了Si,但是没有选择v。我们知道,v在拓扑序列中排在Si前面,如果v没被选择,那么v'被选 择,而Si'是排在v'前面的,这就说明Si已经被遍历过,与前面假设矛盾。综上,不存在Si,它的后代节点没被选过。(这段话要结合算法来理解)前两种 情况它都可以选,第三种情况不存在...证毕。(感觉这种做法好巧妙...我怎么就想不出这种算法...)

    至此,2-sat的研究可以说是告一段落了。

    hdu 1814:

    这道题是2-sat的模板题,比较基础…这题的输出方案比较棘手,说是拓扑排序用不了。

    比较无语的是:这题用论文上的算法1是可以过的...

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <stack>
     4 #include <iostream>
     5 #include <queue>
     6 #define mp make_pair
     7 #define opp(v) ((v+1^1)-1)
     8 using namespace std;
     9 const int maxn=16001,maxm=40001;
    10 
    11 int ta[maxn],lin[maxm],sd[maxm],pos;
    12 void biu(int s,int t) { ++pos; lin[pos]=ta[s]; ta[s]=pos; sd[pos]=t; }
    13 
    14 int n,nn;
    15 int color[maxn];
    16 void init()//--
    17 {
    18     pos=0;
    19     nn=n<<1;
    20     for (int i=1;i<=nn;i++)
    21     {
    22         ta[i]=0;
    23         color[i]=0;
    24     }
    25 }
    26 int jl[maxn],po;
    27 bool dfs(int v)
    28 {
    29     if (color[v]==1) return 1;
    30     if (color[v]==2) return 0;
    31     color[v]=1; color[opp(v)]=2;
    32     jl[++po]=v;
    33     bool flag=1;
    34     for (int i=ta[v];i;i=lin[i])
    35         if (!dfs(sd[i])) { flag=0; break; }
    36     return flag;
    37 }
    38 int main()
    39 {
    40     for (int m;scanf("%d%d",&n,&m)!=EOF;)
    41     {
    42         init();
    43 
    44         for (int a,b;m--;)
    45         {
    46             scanf("%d%d",&a,&b);
    47             if (a>b) swap(a,b);
    48             biu(a,(b+1^1)-1);
    49             biu(b,(a+1^1)-1);
    50         }
    51         bool flag=1;
    52         for (int v=1;v<=nn;v++)
    53         {
    54             if (color[v]) continue;
    55             po=0;
    56             if (!dfs(v))
    57             {
    58                 do color[jl[po]]=color[opp(jl[po])]=0; while (--po);
    59                 if (!dfs(opp(v))) { flag=0; break; }
    60             }
    61         }
    62         if (!flag) puts("NIE");
    63         else
    64             for (int i=1;i<=nn;i++)
    65                 if (color[i]==1) printf("%d
    ",i);
    66     }
    67     return 0;
    68 }
    //2-sat 0

    poj 3678:

    2-sat 好题。理解了2-sat之后,建图不是问题。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <iostream>
     4 #define mp make_pair
     5 #define opp(v) (v<=n?v+n:v-n)
     6 using namespace std;
     7 const int maxn=1001<<1,maxm=1000001<<2;
     8 
     9 int ta[maxn],lin[maxm],sd[maxm],pos;
    10 void biu(int s,int t) { ++pos; lin[pos]=ta[s]; ta[s]=pos; sd[pos]=t; }
    11 
    12 int set[maxn];
    13 int fin(int d)
    14 {
    15     if (d==set[d]) return d;
    16     return set[d]=fin(set[d]);
    17 }
    18 void uion(int x,int y) { set[x]=y; }
    19 
    20 int dfn[maxn],low[maxn],cnt;
    21 int sta[maxn],spo;
    22 bool vis[maxn];
    23 void tarjan(int v)
    24 {
    25     dfn[v]=low[v]=++cnt;
    26     sta[++spo]=v; vis[v]=1;
    27 
    28     for (int i=ta[v];i;i=lin[i])
    29         if (!dfn[sd[i]])
    30         {
    31             tarjan(sd[i]);
    32             low[v]=min(low[v],low[sd[i]]);
    33         }
    34         else if (vis[sd[i]]) low[v]=min(low[v],low[sd[i]]);
    35     if (dfn[v]==low[v])
    36         do
    37         {
    38             set[sta[spo]]=v;
    39             vis[sta[spo]]=0;
    40         } while (sta[spo--]!=v);
    41 }
    42 
    43 int n,nn;
    44 void init()
    45 {
    46     nn=n<<1;
    47     pos=0; cnt=0;
    48     for (int i=1;i<=nn;i++)
    49     {
    50         ta[i]=0;
    51         dfn[i]=low[i]=0;
    52         set[i]=i;
    53     }
    54     
    55     int m;
    56     scanf("%d",&m);
    57     int a,b,c; char op[4];
    58     while (m--)
    59     {
    60         scanf("%d%d%d%s",&a,&b,&c,op);
    61         a++; b++;
    62         if (op[0]=='A')
    63         {
    64             if (c) biu(a+n,a),biu(b+n,b);
    65             else   biu(a,b+n),biu(b,a+n);
    66         }
    67         else if (op[0]=='O')
    68         {
    69             if (c) biu(a+n,b),biu(b+n,a);
    70             else   biu(a,a+n),biu(b,b+n);
    71         }
    72         else
    73         {
    74             if (c) biu(a,b+n),biu(b,a+n),biu(a+n,b),biu(b+n,a);
    75             else   biu(a,b),biu(b,a),biu(a+n,b+n),biu(b+n,a+n);
    76         }
    77     }
    78 }
    79 int main()
    80 {
    81     for (;scanf("%d",&n)!=EOF;)
    82     {
    83         init();
    84         for (int i=1;i<=nn;i++) if (!dfn[i]) tarjan(i);
    85         //for (int i=1;i<=nn;i++) cout<<i-1<<" "<<set[i]<<" "<<dfn[i]<<" "<<low[i]<<endl;
    86         bool flag=1;
    87         for (int i=1;i<=n;i++)
    88             if (fin(i)==fin(i+n)) { flag=0; break; } //low[i]==low[i+n] -_-
    89         printf("%s
    ",flag?"YES":"NO");
    90     }
    91     return 0;
    92 }
    //2-sat 1

    小小感悟:

    做了两道题了,也算是对2-sat有了一定的认识了。来说说我对2-sat的理解吧。

    2-sat 中最重要的概念我认为是建图中的必要关系。比如两个点Si, Sj互斥,那么Si选了之后就必须选Sj',Sj同理。只要了解这个建图的原理,poj 3678这种稍有变化的题对我们来说就不是难事了。

    hdu 3622:

    二分+2-sat判定。精度要到1e-4才行。我觉得是因为有可能r-l<1e-3,但l=1.0049,r=1.0051。具体解决方法就是把每次判断l和r所确定的端点值是否一样,不一样的话继续二分。不过这方法可行度不高...在做题的时候,尽量把eps定得低一些吧。(我觉得小3个数量级应该够了)

     1 //11639828    2014-09-12 08:49:10    Accepted    3622    343MS    616K    1735 B    G++    TofE
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <iostream>
     5 #define mp make_pair
     6 #define opp(v) ((v+1^1)-1)
     7 #define dbg(x) cout<<#x<<"="<<x<<endl
     8 using namespace std;
     9 const int maxn=101<<1,maxm=40001;
    10 
    11 int ta[maxn],lin[maxm],sd[maxm],pos;
    12 void biu(int s,int t) { ++pos; lin[pos]=ta[s]; ta[s]=pos; sd[pos]=t; }
    13 
    14 int dfn[maxn],low[maxn],cnt;
    15 int sta[maxn],spo;
    16 bool vis[maxn];
    17 int set[maxn];
    18 void tarjan(int v)
    19 {
    20     dfn[v]=low[v]=++cnt;
    21     sta[++spo]=v; vis[v]=1;
    22 
    23     for (int i=ta[v];i;i=lin[i])
    24         if (!dfn[sd[i]])
    25         {
    26             tarjan(sd[i]);
    27             low[v]=min(low[v],low[sd[i]]);
    28         }
    29         else if (vis[sd[i]]) low[v]=min(low[v],low[sd[i]]);
    30     if (dfn[v]==low[v])
    31         do
    32         {
    33             set[sta[spo]]=v;
    34             vis[sta[spo]]=0;
    35         } while (sta[spo--]!=v);
    36 }
    37 
    38 struct pot{
    39     double x,y;
    40 }wu[maxn];
    41 
    42 int n,nn;
    43 void init()
    44 {
    45     nn=n<<1;
    46     for (int i=1;i<=nn;i+=2)
    47         for (int j=0;j<2;j++)
    48             scanf("%lf%lf",&wu[i+j].x,&wu[i+j].y);
    49 }
    50 bool co(int i,int j,double R)
    51 {
    52     if (4*R*R>(wu[i].x-wu[j].x)*(wu[i].x-wu[j].x)+(wu[i].y-wu[j].y)*(wu[i].y-wu[j].y)) return 1;
    53     return 0;
    54 }
    55 bool judge(double R)
    56 {
    57     pos=0; cnt=0;
    58     for (int i=1;i<=nn;i++)
    59     {
    60         ta[i]=dfn[i]=low[i]=0;
    61         set[i]=i;
    62     }
    63     for (int i=1;i<=nn;i+=2)
    64         for (int j=i+2;j<=nn;j++)
    65         {
    66             if (co(i,j,R))   biu(i,opp(j)),biu(j,opp(i));
    67             if (co(i+1,j,R)) biu(i+1,opp(j)),biu(j,opp(i+1));
    68         }
    69     for (int i=1;i<=nn;i++) if (!dfn[i]) tarjan(i);
    70     for (int i=1;i<=nn;i+=2) if (set[i]==set[i+1]) return 0;
    71     return 1;
    72 }
    73 void solve()
    74 {
    75     double l=0,r=30000,mid;
    76     while (r-l>=1e-4) //1e-3就会挂...
    77     {
    78         mid=(l+r)/2;
    79         if (judge(mid)) l=mid;
    80         else             r=mid;
    81     }
    82     printf("%.2f
    ",l);
    83 }
    84 int main()
    85 {
    86     for (;scanf("%d",&n)!=EOF;)
    87     {
    88         init();
    89         solve();
    90     }
    91     return 0;
    92 }
    //2-sat 2

    (待续...)

    ooyyloo原创,转载请注明出处。

  • 相关阅读:
    PHP $_POST 变量
    PHP $_GET 变量
    PHP 完整表单实例
    PHP 表单
    PHP 表单
    PHP 表单验证
    00_前情回顾
    18_今日回顾
    VMware 12PRO安装Mac OS X 10.10.5
    05_传智播客iOS视频教程_第一个OC程序
  • 原文地址:https://www.cnblogs.com/monmonde/p/3966816.html
Copyright © 2020-2023  润新知