• (转)2sat 专题


    【2-sat】专题~

     

    2-sat是一个逻辑性很强的算法,但是其套路比较固定,所以不是很热,题目很少,但也不乏AC后让人大呼爽快的好题,下面放出两篇极品论文还有几道题目的题解以供交流~~

      

    2-sat学习:

    对称性解决2-sat的ppt

    赵爽的2-SAT解法浅析论文

      

    强连通判是否存在解:

    HDU 3062 Party [入门]

    2-sat入门题,建图后求强连通判断是否有解即可

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x<y?x:y)
    5 #define N 2005
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 size=step=scc=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 int main(){
    51 int n,m;
    52 while(~scanf("%d%d",&n,&m)){
    53 Init();
    54 for(int i=0;i<m;i++){
    55 int a1,a2,c1,c2;
    56 scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
    57 Insert((a1<<1)+c1,(a2<<1|1)-c2);
    58 Insert((a2<<1)+c2,(a1<<1|1)-c1);
    59 }
    60 for(int i=0;i<2*n;i++){
    61 if(dfn[i]==-1) Tarjan(i);
    62 }
    63 bool flag=true;
    64 for(int i=0;i<n;i++){
    65 if(blg[i<<1]==blg[i<<1|1]){
    66 flag=false;
    67 break;
    68 }
    69 }
    70 puts(flag?"YES":"NO");
    71 }
    72 }

      

    HDU 1824 Let's go home [基础]

    把每队的两名队员当作一个整体,队长和队员为相对状态,建图求强连通即可

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 #include<cstdlib>
    4 usingnamespace std;
    5 #define MIN(x,y) (x>y?y:x)
    6 #define N 2005
    7
    8 struct Edge{
    9 int vtx,next;
    10 }E[999999];
    11 int head[N],size;
    12 int dfn[N],low[N],blg[N],step,scc;
    13 int stk[N],top;
    14 bool ins[N];
    15
    16 void Init(){
    17 memset(head,-1,sizeof(head));
    18 memset(dfn,-1,sizeof(dfn));
    19 memset(ins,false,sizeof(ins));
    20 size=step=scc=0; top=-1;
    21 }
    22
    23 void Insert(int u,int v){
    24 E[size].vtx=v;
    25 E[size].next=head[u];
    26 head[u]=size++;
    27 }
    28
    29 void Tarjan(int u){
    30 stk[++top]=u; ins[u]=true;
    31 dfn[u]=low[u]=step++;
    32 for(int i=head[u];i!=-1;i=E[i].next){
    33 int v=E[i].vtx;
    34 if(dfn[v]==-1){
    35 Tarjan(v);
    36 low[u]=MIN(low[u],low[v]);
    37 }elseif(ins[v]){
    38 low[u]=MIN(low[u],dfn[v]);
    39 }
    40 };
    41 if(low[u]==dfn[u]){
    42 for(int v=-1;v!=u;top--){
    43 v=stk[top];
    44 ins[v]=false;
    45 blg[v]=scc;
    46 }
    47 scc++;
    48 }
    49 }
    50
    51 int B[3005];
    52 int main(){
    53 int n,m;
    54 while(~scanf("%d%d",&n,&m)){
    55 for(int i=0;i<n;i++){
    56 int l,s1,s2;
    57 scanf("%d%d%d",&l,&s1,&s2);
    58 B[l]=i<<1;
    59 B[s1]=i<<1|1;
    60 B[s2]=i<<1|1;
    61 }
    62 Init();
    63 for(int i=0;i<m;i++){
    64 int a,b;
    65 scanf("%d%d",&a,&b);
    66 Insert(B[a],B[b]^1);
    67 Insert(B[b],B[a]^1);
    68 }
    69 for(int i=0;i<n*2;i++){
    70 if(dfn[i]==-1) Tarjan(i);
    71 }
    72 bool flag=true;
    73 for(int i=0;i<n;i++){
    74 if(blg[i<<1]==blg[i<<1|1]){
    75 puts("no");
    76 main();
    77 exit(0);
    78 }
    79 }
    80 puts("yes");
    81 }
    82 }

      

    POJ 3207 Ikki’s Story IV - Panda’s Trick [基础]

    判断两段是否相交,如果相交的话不能在同侧,在两侧为相对状态,建图求强连通

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 1005
    6
    7 struct Edge{
    8 int vtx,next;
    9 Edge(){}
    10 Edge(int v,int n):
    11 vtx(v),next(n){}
    12 }E[999999];
    13 int head[N],size;
    14 int dfn[N],low[N],blg[N],step,scc;
    15 int stk[N],top;
    16 bool ins[N];
    17
    18 void Init(){
    19 memset(head,-1,sizeof(head));
    20 memset(dfn,-1,sizeof(dfn));
    21 memset(ins,false,sizeof(ins));
    22 size=step=scc=0; top=-1;
    23 }
    24
    25 void Insert(int u,int v){
    26 E[size]=Edge(v,head[u]);
    27 head[u]=size++;
    28 }
    29
    30 void Tarjan(int u){
    31 stk[++top]=u; ins[u]=true;
    32 dfn[u]=low[u]=step++;
    33 for(int i=head[u];i!=-1;i=E[i].next){
    34 int v=E[i].vtx;
    35 if(dfn[v]==-1){
    36 Tarjan(v);
    37 low[u]=MIN(low[u],low[v]);
    38 }elseif(ins[v]){
    39 low[u]=MIN(low[u],dfn[v]);
    40 }
    41 }
    42 if(low[u]==dfn[u]){
    43 for(int v=-1;v!=u;top--){
    44 v=stk[top];
    45 ins[v]=false;
    46 blg[v]=scc;
    47 }
    48 scc++;
    49 }
    50 }
    51
    52 int l[505],r[505];
    53 int main(){
    54 int n,m;
    55 while(~scanf("%d%d",&n,&m)){
    56 for(int i=0;i<m;i++){
    57 scanf("%d%d",&l[i],&r[i]);
    58 if(l[i]>r[i]){
    59 int tmp=l[i]; l[i]=r[i]; r[i]=tmp;
    60 }
    61 }
    62 Init();
    63 for(int i=0;i<m;i++){
    64 for(int j=i+1;j<m;j++){
    65 int cnt=0;
    66 if(l[i]>l[j]&&l[i]<r[j]) cnt++;
    67 if(r[i]>l[j]&&r[i]<r[j]) cnt++;
    68 if(cnt==1){
    69 Insert(i<<1,j<<1|1);
    70 Insert(j<<1|1,i<<1);
    71 Insert(i<<1|1,j<<1);
    72 Insert(j<<1,i<<1|1);
    73 }
    74 }
    75 }
    76 for(int i=0;i<2*m;i++){
    77 if(dfn[i]==-1) Tarjan(i);
    78 }
    79 bool flag=true;
    80 for(int i=0;i<m;i++){
    81 if(blg[i<<1]==blg[i<<1|1]){
    82 flag=false;
    83 break;
    84 }
    85 }
    86 puts(flag?"panda is telling the truth...":"the evil panda is lying again");
    87 }
    88 }

      

    POJ 3678 Katu Puzzle [中等]

    2-sat建图题,把每个值是1(a)和0(~a)为两种状态,分清楚各种操作的本质就很简单了

    AND 结果为1:建边 ~x->x,~y->y (两个数必须全为1)

    AND 结果为0:建边 y->~x,x->~y (两个数至少有一个为0)

    OR 结果为1:建边 ~x->y,~y->x (两个数至少有一个为1)

    OR 结果为0:建边 x->~x,y->~y (两个数必须全为0)

    XOR 结果为1:建边 x->~y,y->~x,~y->x,~x->y (两个数必须不同)

    XOR 结果为0:建边 x->y,y->x,~x->~y,~y->~x (两个数必须相同)

    然后求强联通即可

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 2005
    6
    7 struct Edge{
    8 int vtx,next;
    9 Edge(){}
    10 Edge(int v,int n):
    11 vtx(v),next(n){}
    12 }E[999999];
    13 int head[N],size;
    14 int dfn[N],low[N],blg[N],step,scc;
    15 int stk[N],top;
    16 bool ins[N];
    17
    18 void Init(){
    19 memset(head,-1,sizeof(head));
    20 memset(dfn,-1,sizeof(dfn));
    21 memset(ins,false,sizeof(ins));
    22 size=step=scc=0; top=-1;
    23 }
    24
    25 void Insert(int u,int v){
    26 E[size]=Edge(v,head[u]);
    27 head[u]=size++;
    28 }
    29
    30 void Tarjan(int u){
    31 stk[++top]=u; ins[u]=true;
    32 dfn[u]=low[u]=step++;
    33 for(int i=head[u];i!=-1;i=E[i].next){
    34 int v=E[i].vtx;
    35 if(dfn[v]==-1){
    36 Tarjan(v);
    37 low[u]=MIN(low[u],low[v]);
    38 }elseif(ins[v]){
    39 low[u]=MIN(low[u],dfn[v]);
    40 }
    41 }
    42 if(low[u]==dfn[u]){
    43 for(int v=-1;v!=u;top--){
    44 v=stk[top];
    45 ins[v]=false;
    46 blg[v]=scc;
    47 }
    48 scc++;
    49 }
    50 }
    51
    52 int main(){
    53 int n,m;
    54 while(~scanf("%d%d",&n,&m)){
    55 Init();
    56 for(int i=0;i<m;i++){
    57 int a,b,c;
    58 char cmd[5];
    59 scanf("%d%d%d %s",&a,&b,&c,cmd);
    60 if(cmd[0]=='A'){
    61 if(c==1){
    62 Insert(a<<1|1,a<<1);
    63 Insert(b<<1|1,b<<1);
    64 }else{
    65 Insert(a<<1,b<<1|1);
    66 Insert(b<<1,a<<1|1);
    67 }
    68 }elseif(cmd[0]=='O'){
    69 if(c==1){
    70 Insert(a<<1|1,b<<1);
    71 Insert(b<<1|1,a<<1);
    72 }else{
    73 Insert(a<<1,a<<1|1);
    74 Insert(b<<1,b<<1|1);
    75 }
    76 }elseif(cmd[0]=='X'){
    77 if(c==1){
    78 Insert(a<<1,b<<1|1);
    79 Insert(a<<1|1,b<<1);
    80 Insert(b<<1,a<<1|1);
    81 Insert(b<<1|1,a<<1);
    82 }else{
    83 Insert(a<<1,b<<1);
    84 Insert(a<<1|1,b<<1|1);
    85 Insert(b<<1,a<<1);
    86 Insert(b<<1|1,a<<1|1);
    87 }
    88 }
    89 }
    90 for(int i=0;i<n*2;i++){
    91 if(dfn[i]==-1) Tarjan(i);
    92 }
    93 bool flag=true;
    94 for(int i=0;i<n;i++){
    95 if(blg[i<<1]==blg[i<<1|1]){flag=false;break;}
    96 }
    97 puts(flag?"YES":"NO");
    98 }
    99 }

      

    二分+强联通判解:

    HDU 3622 Bomb Game [中等]

    比较裸的 二分+2-sat

    View Code
      1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 205
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 size=step=scc=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 inline double len(int ax,int ay,int bx,int by){
    51 return (double)((ax-bx)*(ax-bx)+(ay-by)*(ay-by));
    52 }
    53
    54 int lx[105],ly[105],rx[105],ry[105];
    55 int main(){
    56 int n;
    57 while(~scanf("%d",&n)){
    58 for(int i=0;i<n;i++){
    59 scanf("%d%d%d%d",&lx[i],&ly[i],&rx[i],&ry[i]);
    60 }
    61 double low=0.0,high=10000.0;
    62 double mid=(low+high)/2.0,ans=mid;
    63 while(high-low>1e-4){
    64 Init();
    65 double ll=mid*mid;
    66 for(int i=0;i<n;i++){
    67 for(int j=0;j<n;j++){
    68 if(i==j) continue;
    69 if(len(lx[i],ly[i],lx[j],ly[j])<ll){
    70 Insert(i<<1,j<<1|1);
    71 Insert(j<<1,i<<1|1);
    72 }
    73 if(len(rx[i],ry[i],rx[j],ry[j])<ll){
    74 Insert(i<<1|1,j<<1);
    75 Insert(j<<1|1,i<<1);
    76 }
    77 if(len(lx[i],ly[i],rx[j],ry[j])<ll){
    78 Insert(i<<1,j<<1);
    79 Insert(j<<1|1,i<<1|1);
    80 }
    81 if(len(rx[i],ry[i],lx[j],ly[j])<ll){
    82 Insert(i<<1|1,j<<1|1);
    83 Insert(j<<1,i<<1);
    84 }
    85 }
    86 }
    87 for(int i=0;i<(n<<1);i++){
    88 if(dfn[i]==-1) Tarjan(i);
    89 }
    90 bool flag=true;
    91 for(int i=0;i<n;i++){
    92 if(blg[i<<1]==blg[i<<1|1]){flag=false;break;}
    93 }
    94 if(flag){
    95 low=(ans=mid);
    96 }else{
    97 high=mid;
    98 }
    99 mid=(low+high)/2.0;
    100 }
    101 printf("%.2lf\n",ans/2);
    102 }
    103 }

      

    POJ 2296 Map Labeler [中等]

    几种情况讨论一下在上边(a),在下边(~a),假设点i在点j的上

    如果|xi-xj|>=mid continue;

    否则|yi-yj|>=2*mid continue;

    否则|yi-yj|>=mid 建边 j->i,~i->~j;

    否则|yi-yj|>0 建边 ~i->i,j->~j;

    否则|yi-yj|==0 建边 i->~j,~i->j,j->~i,~j->i;

    等于0的情况很容易忘记考虑

    View Code
      1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 205
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 scc=step=size=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 inline int ABS(int x){
    51 if(x<0) return-x;
    52 return x;
    53 }
    54 int px[N],py[N];
    55 int main(){
    56 int t;
    57 scanf("%d",&t);
    58 while(t--){
    59 int n;
    60 scanf("%d",&n);
    61 for(int i=0;i<n;i++){
    62 scanf("%d%d",&px[i],&py[i]);
    63 }
    64 int low=0,high=10000;
    65 int mid=(low+high)>>1,ans=mid;
    66 while(low<=high){
    67 Init();
    68 for(int i=0;i<n;i++){
    69 for(int j=i+1;j<n;j++){
    70 if(ABS(px[i]-px[j])>=mid) continue;
    71 if(ABS(py[i]-py[j])>=(mid<<1)) continue;
    72 elseif(ABS(py[i]-py[j])>=mid){
    73 if(py[i]>py[j]){
    74 Insert(i<<1,j<<1);
    75 Insert(j<<1|1,i<<1|1);
    76 }else{
    77 Insert(i<<1|1,j<<1|1);
    78 Insert(j<<1,i<<1);
    79 }
    80 }else{
    81 if(py[i]<py[j]){
    82 Insert(i<<1|1,i<<1);
    83 Insert(j<<1,j<<1|1);
    84 }elseif(py[i]>py[j]){
    85 Insert(i<<1,i<<1|1);
    86 Insert(j<<1|1,j<<1);
    87 }else{
    88 Insert(i<<1,j<<1|1);
    89 Insert(i<<1|1,j<<1);
    90 Insert(j<<1,i<<1|1);
    91 Insert(j<<1|1,i<<1);
    92 }
    93 }
    94 }
    95 }
    96 for(int i=0;i<(n<<1);i++){
    97 if(dfn[i]==-1) Tarjan(i);
    98 }
    99 bool flag=true;
    100 for(int i=0;i<n;i++){
    101 if(blg[i<<1]==blg[i<<1|1]){
    102 flag=false; break;
    103 }
    104 }
    105 if(flag){
    106 low=(ans=mid)+1;
    107 }else{
    108 high=mid-1;
    109 }
    110 mid=(low+high)>>1;
    111 }
    112 printf("%d\n",ans);
    113 }
    114 }

      

    HDU 3715 Go Deeper [中等]

    x值为1(a)和0(~a)两种情况

    c=0时,建边 ~a->b,~b->a

    c=1时,建边 a->b,~a->~b,b->a,~b->~a

    c=2时,建边 a->~b,b->~a

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 405
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 size=step=scc=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 int a[10005],b[10005],c[10005];
    51 int main(){
    52 int t;
    53 scanf("%d",&t);
    54 while(t--){
    55 int n,m;
    56 scanf("%d%d",&n,&m);
    57 for(int i=0;i<m;i++){
    58 scanf("%d%d%d",&a[i],&b[i],&c[i]);
    59 }
    60 int low=0,high=m;
    61 int mid=(low+high)>>1,ans=mid;
    62 while(low<=high){
    63 Init();
    64 for(int i=0;i<mid;i++){
    65 if(c[i]==0){
    66 Insert(a[i]<<1,b[i]<<1|1);
    67 Insert(b[i]<<1,a[i]<<1|1);
    68 }elseif(c[i]==1){
    69 Insert(a[i]<<1,b[i]<<1);
    70 Insert(a[i]<<1|1,b[i]<<1|1);
    71 Insert(b[i]<<1,a[i]<<1);
    72 Insert(b[i]<<1|1,a[i]<<1|1);
    73 }elseif(c[i]==2){
    74 Insert(a[i]<<1|1,b[i]<<1);
    75 Insert(b[i]<<1|1,a[i]<<1);
    76 }
    77 }
    78 for(int i=0;i<(n<<1);i++){
    79 if(dfn[i]==-1) Tarjan(i);
    80 }
    81 bool flag=true;
    82 for(int i=0;i<n;i++){
    83 if(blg[i<<1]==blg[i<<1|1]){
    84 flag=false; break;
    85 }
    86 }
    87 if(flag){
    88 low=(ans=mid)+1;
    89 }else{
    90 high=mid-1;
    91 }
    92 mid=(low+high)>>1;
    93 }
    94 printf("%d\n",ans);
    95 }
    96 }

      

    POJ 2749 HDU 1815 Building roads [较难]

    较难是难在读题上,题目意思是说每个仓库都必须与两个传送点其中的一个且只有一个建路(仓库与传送点以及传送点与传送点之间的路的距离是曼哈顿距离),在满足一些like与hate的关系的情况下要求任意两个仓库的距离的最大值最小(这里指沿道路的距离)

    题目理解的话就很简单了,在二分前先把like和hate的关系全部建好(连在s1(a),连在s2(~a))

    like: x->y,~x->~y,y->x,y->~x

    hate: x->~y,~x->y,y->~x,~y->x;

    然后二分距离(d为s1与s2的距离)

    dis_s1[x]+dis_s1[y]>mid 建边 x->~y,y->~x

    dis_s2[x]+dis_s2[y]>mid 建边 ~x->y,~y->x

    dis_s1[x]+dis_s2[y]+d>mid 建边 x->y,~y->~x

    dis_s2[x]+dis_s1[y]+d>mid 建边 ~x->~y,y->x

    View Code
      1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 1005
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999],tE[999999];
    10 int head[N],size;
    11 int thead[N],tsize;
    12 int dfn[N],low[N],blg[N],step,scc;
    13 int stk[N],top;
    14 bool ins[N];
    15
    16 void Init(){
    17 memset(head,-1,sizeof(head));
    18 memset(thead,-1,sizeof(thead));
    19 memset(dfn,-1,sizeof(dfn));
    20 memset(ins,false,sizeof(ins));
    21 step=scc=0; top=-1;
    22 tsize=size=0;
    23 }
    24
    25 void tInit(){
    26 memset(thead,-1,sizeof(thead));
    27 memset(dfn,-1,sizeof(dfn));
    28 memset(ins,false,sizeof(ins));
    29 tsize=step=scc=0; top=-1;
    30 }
    31
    32 void Insert(int u,int v){
    33 E[size].vtx=v;
    34 E[size].next=head[u];
    35 head[u]=size++;
    36 }
    37 void tInsert(int u,int v){
    38 tE[tsize].vtx=v;
    39 tE[tsize].next=thead[u];
    40 thead[u]=tsize++;
    41 }
    42
    43 void Tarjan(int u){
    44 stk[++top]=u; ins[u]=true;
    45 dfn[u]=low[u]=step++;
    46 for(int i=head[u];i!=-1;i=E[i].next){
    47 int v=E[i].vtx;
    48 if(dfn[v]==-1){
    49 Tarjan(v);
    50 low[u]=MIN(low[u],low[v]);
    51 }elseif(ins[v]){
    52 low[u]=MIN(low[u],dfn[v]);
    53 }
    54 }
    55 for(int i=thead[u];i!=-1;i=tE[i].next){
    56 int v=tE[i].vtx;
    57 if(dfn[v]==-1){
    58 Tarjan(v);
    59 low[u]=MIN(low[u],low[v]);
    60 }elseif(ins[v]){
    61 low[u]=MIN(low[u],dfn[v]);
    62 }
    63 }
    64 if(low[u]==dfn[u]){
    65 for(int v=-1;v!=u;top--){
    66 v=stk[top];
    67 ins[v]=false;
    68 blg[v]=scc;
    69 }
    70 scc++;
    71 }
    72 }
    73
    74 int s1x,s1y,s2x,s2y;
    75 int dis[505][2];
    76 int gdis(int x1,int y1,int x2,int y2){
    77 int d1=x1-x2; if(d1<0) d1=-d1;
    78 int d2=y1-y2; if(d2<0) d2=-d2;
    79 return d1+d2;
    80 }
    81
    82 int main(){
    83 int n,a,b;
    84 while(~scanf("%d%d%d",&n,&a,&b)){
    85 scanf("%d%d%d%d",&s1x,&s1y,&s2x,&s2y);
    86 int d=gdis(s1x,s1y,s2x,s2y);
    87
    88 int low=8000000,high=8000000;
    89 for(int i=0;i<n;i++){
    90 int x,y;
    91 scanf("%d%d",&x,&y);
    92 dis[i][0]=gdis(x,y,s1x,s1y);
    93 if(low>dis[i][0]) low=dis[i][0];
    94 dis[i][1]=gdis(x,y,s2x,s2y);
    95 if(low>dis[i][1]) low=dis[i][1];
    96 }
    97 Init();
    98 for(int i=0;i<a;i++){
    99 int l,r;
    100 scanf("%d%d",&l,&r);
    101 l--; r--;
    102 Insert(l<<1,r<<1|1);
    103 Insert(l<<1|1,r<<1);
    104 Insert(r<<1,l<<1|1);
    105 Insert(r<<1|1,l<<1);
    106 }
    107 for(int i=0;i<b;i++){
    108 int l,r;
    109 scanf("%d%d",&l,&r);
    110 l--; r--;
    111 Insert(l<<1,r<<1);
    112 Insert(l<<1|1,r<<1|1);
    113 Insert(r<<1,l<<1);
    114 Insert(r<<1|1,l<<1|1);
    115 }
    116 for(int i=0;i<(n<<1);i++){
    117 if(dfn[i]==-1) Tarjan(i);
    118 }
    119 bool flag=true;
    120 for(int i=0;i<n;i++){
    121 if(blg[i<<1]==blg[i<<1|1]){flag=false; break;}
    122 }
    123 if(!flag){
    124 puts("-1");
    125 continue;
    126 }
    127 int mid=(low+high)>>1,ans=0;
    128 while(low<=high){
    129 tInit();
    130 for(int i=0;i<n;i++){
    131 for(int j=i+1;j<n;j++){
    132 if(dis[i][0]+dis[j][0]>mid){
    133 tInsert(i<<1,j<<1|1);
    134 tInsert(j<<1,i<<1|1);
    135 }
    136 if(dis[i][0]+dis[j][1]+d>mid){
    137 tInsert(i<<1,j<<1);
    138 tInsert(j<<1|1,i<<1|1);
    139 }
    140 if(dis[i][1]+dis[j][1]>mid){
    141 tInsert(i<<1|1,j<<1);
    142 tInsert(j<<1|1,i<<1);
    143 }
    144 if(dis[i][1]+dis[j][0]+d>mid){
    145 tInsert(i<<1|1,j<<1|1);
    146 tInsert(j<<1,i<<1);
    147 }
    148 }
    149 }
    150 for(int i=0;i<(n<<1);i++){
    151 if(dfn[i]==-1) Tarjan(i);
    152 }
    153 bool flag=true;
    154 for(int i=0;i<n;i++){
    155 if(blg[i<<1]==blg[i<<1|1]){flag=false; break;}
    156 }
    157 if(flag){
    158 high=(ans=mid)-1;
    159 }else{
    160 low=mid+1;
    161 }
    162 mid=(low+high)>>1;
    163 }
    164 printf("%d\n",ans);
    165 }
    166 }

      

    POJ 2723 Get Luffy Out [较难]

    两把钥匙为一组,以一个为a,另一个就为~a

    对于每一扇门的两把锁X和Y,对应钥匙为x和y,如果我们用了与x一组的钥匙~x,那么x钥匙就不能用了,我们就必须去打开Y锁,使用y钥匙,即边 ~x->y,~y->x

    二分能打开门的个数,强连通判解

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 2050
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 size=step=scc=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 int opp[N];
    51 int dl[2050],dr[2050];
    52 int main(){
    53 int n,m;
    54 while(scanf("%d%d",&n,&m),n||m){
    55 for(int i=0;i<n;i++){
    56 int l,r;
    57 scanf("%d%d",&l,&r);
    58 opp[l]=r;
    59 opp[r]=l;
    60 }
    61 n<<=1;
    62 for(int i=0;i<m;i++){
    63 scanf("%d%d",&dl[i],&dr[i]);
    64 }
    65
    66 int low=0,high=m;
    67 int mid=(low+high)>>1,ans=mid;
    68 while(low<=high){
    69 Init();
    70 for(int i=0;i<mid;i++){
    71 Insert(opp[dl[i]],dr[i]);
    72 Insert(opp[dr[i]],dl[i]);
    73 }
    74 for(int i=0;i<n;i++){
    75 if(dfn[i]==-1) Tarjan(i);
    76 }
    77 bool flag=true;
    78 for(int i=0;i<n;i++){
    79 if(blg[i]==blg[opp[i]]){
    80 flag=false;
    81 break;
    82 }
    83 }
    84 if(flag) low=(ans=mid)+1;
    85 else high=mid-1;
    86 mid=(low+high)>>1;
    87 }
    88 printf("%d\n",ans);
    89
    90
    91 }
    92 }

      

    HDU 1816 Get Luffy Out * [较难]

    上题的加强版,这题中一把钥匙可以同时属于多组,我们把每把钥匙使用(a)和不使用(~a)为两个状态,先根据组建边,如果一个组x和y两把钥匙,那么有x->~y,y->~x,然后就和上题一样了

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 4200
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],scc,step;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 size=step=scc=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 int kl[1050],kr[1050];
    51 int dl[2100],dr[2100];
    52 int main(){
    53 int n,m;
    54 while(scanf("%d%d",&n,&m),n||m){
    55 for(int i=0;i<n;i++){
    56 scanf("%d%d",&kl[i],&kr[i]);
    57 }
    58 for(int i=0;i<m;i++){
    59 scanf("%d%d",&dl[i],&dr[i]);
    60 }
    61
    62 int low=0,high=m;
    63 int mid=(low+high)>>1,ans=mid;
    64 while(low<=high){
    65 Init();
    66 for(int i=0;i<n;i++){
    67 Insert(kl[i]<<1,kr[i]<<1|1);
    68 Insert(kr[i]<<1,kl[i]<<1|1);
    69 }
    70 for(int i=0;i<mid;i++){
    71 Insert(dl[i]<<1|1,dr[i]<<1);
    72 Insert(dr[i]<<1|1,dl[i]<<1);
    73 }
    74 for(int i=0;i<(n<<1);i++){
    75 if(dfn[i]==-1) Tarjan(i);
    76 }
    77 bool flag=true;
    78 for(int i=0;i<n;i++){
    79 if(blg[i<<1]==blg[i<<1|1]){
    80 flag=false;break;
    81 }
    82 }
    83 if(flag){
    84 low=(ans=mid)+1;
    85 }else{
    86 high=mid-1;
    87 }
    88 mid=(low+high)>>1;
    89 }
    90 printf("%d\n",ans);
    91 }
    92 }

      

    求方案:

    赵爽的论文中提到将相对点染为蓝色后要将其子孙全部染为蓝色,今天看代码时发现这个操作完全是多余的,因为染为红色的点是每次找入度为0的点染色的,那么根据他的对称性,染为蓝色的点的出度也是为0的,那么他的子孙也只能是已经染过蓝色的点了,所以这里直接按照拓扑序贪心就行了(11/8/3更新)

    HDU 1814 Peaceful Commission [中等]

    因为要求最小字典序解,所以就不能用强连通+拓扑排序的方法做了,直接用暴力的方法求出解即可,复杂度有点高啊

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 #include<vector>
    4 usingnamespace std;
    5
    6 vector<int> gra[16005];
    7 constint R=1;
    8 constint B=2;
    9 constint W=0;
    10 int col[16005],n;
    11 int cnt,ans[16005];
    12 bool dfs(int u) {
    13 int size=gra[u].size();
    14 if(col[u]==B) returnfalse;
    15 if(col[u]==R) returntrue;
    16 col[u]=R;
    17 col[u^1]=B;
    18 ans[cnt++]=u;
    19 for(int i=0;i<size;i++){
    20 int v=gra[u][i];
    21 if(!dfs(v)) returnfalse;
    22 }
    23 returntrue;
    24 }
    25
    26 bool solve() {
    27 memset(col,0,sizeof(col));
    28 for(int i=0;i<n;i++){
    29 if(col[i]) continue;
    30 cnt=0;
    31 if(!dfs(i)){
    32 for(int j=0;j<cnt;j++){
    33 col[ans[j]]=W;
    34 col[ans[j]^1]=W;
    35 }
    36 if(!dfs(i^1)) returnfalse;
    37 }
    38 }
    39 returntrue;
    40 }
    41
    42 int main (){
    43 int m;
    44 while(~scanf("%d%d",&n,&m)) {
    45 n<<=1;
    46 for(int i=0;i<n;i++) gra[i].clear();
    47 for(int i=0;i<m;i++){
    48 int a,b;
    49 scanf("%d%d",&a,&b);
    50 a--; b--;
    51 gra[a].push_back(b^1);
    52 gra[b].push_back(a^1);
    53 }
    54 if(solve()){
    55 for(int i=0;i<n;i++){
    56 if(col[i]==R) printf("%d\n",i+1);
    57 }
    58 }else puts("NIE");
    59 }
    60 }

      

    POJ 3683 Priest John’s Busiest Day [中等]

    对时间处理之后就是比较裸的2-sat求可行解了

    View Code
      1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 4005
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[2999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 step=size=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 constint W=0;
    51 constint R=1;
    52 constint B=2;
    53 int deg[N],col[N],opp[N];
    54 int que[N],ss,ee;
    55
    56 void topo(){
    57 ss=ee=0;
    58 memset(col,W,sizeof(col));
    59 for(int i=0;i<scc;i++){
    60 if(!deg[i]) que[ee++]=i;
    61 }
    62 while(ss<ee){
    63 int u=que[ss++];
    64 if(col[u]) continue;
    65 col[u]=R;
    66 col[opp[u]]=B;
    67 for(int i=head[u];i!=-1;i=E[i].next){
    68 int v=E[i].vtx; deg[v]--;
    69 if(!deg[v]) que[ee++]=v;
    70 }
    71 }
    72 }
    73
    74 int l[N],r[N],len[N];
    75 int main(){
    76 int n;
    77 while(~scanf("%d",&n)){
    78 for(int i=0;i<n;i++){
    79 int lh,lm,rh,rm;
    80 scanf("%d:%d %d:%d %d",&lh,&lm,&rh,&rm,&len[i]);
    81 l[i]=lh*60+lm;
    82 r[i]=rh*60+rm;
    83 }
    84 Init(); scc=0;
    85 for(int i=0;i<n;i++){
    86 for(int j=i+1;j<n;j++){
    87 if(l[i]<l[j]+len[j]&&l[i]+len[i]>l[j]){
    88 Insert(i<<1,j<<1|1);
    89 Insert(j<<1,i<<1|1);
    90 }
    91 if(l[i]<r[j]&&l[i]+len[i]>r[j]-len[j]){
    92 Insert(i<<1,j<<1);
    93 Insert(j<<1|1,i<<1|1);
    94 }
    95 if(r[i]-len[i]<l[j]+len[j]&&r[i]>l[j]){
    96 Insert(i<<1|1,j<<1|1);
    97 Insert(j<<1,i<<1);
    98 }
    99 if(r[i]-len[i]<r[j]&&r[i]>r[j]-len[j]){
    100 Insert(i<<1|1,j<<1);
    101 Insert(j<<1|1,i<<1);
    102 }
    103 }
    104 }
    105 for(int i=0;i<(n<<1);i++){
    106 if(dfn[i]==-1) Tarjan(i);
    107 }
    108 bool flag=true;
    109 for(int i=0;i<n;i++){
    110 opp[blg[i<<1]]=blg[i<<1|1];
    111 opp[blg[i<<1|1]]=blg[i<<1];
    112 if(blg[i<<1]==blg[i<<1|1]){
    113 flag=false; break;
    114 }
    115 }
    116 if(flag){
    117 Init();
    118 memset(deg,0,sizeof(deg));
    119 for(int i=0;i<n;i++){
    120 for(int j=i+1;j<n;j++){
    121 int li=blg[i<<1],ri=blg[i<<1|1];
    122 int lj=blg[j<<1],rj=blg[j<<1|1];
    123 if(li!=rj&&lj!=ri){
    124 if(l[i]<l[j]+len[j]&&l[i]+len[i]>l[j]){
    125 Insert(ri,lj); deg[lj]++;
    126 Insert(rj,li); deg[li]++;
    127 }
    128 if(r[i]-len[i]<r[j]&&r[i]>r[j]-len[j]){
    129 Insert(lj,ri); deg[ri]++;
    130 Insert(li,rj); deg[rj]++;
    131 }
    132 }
    133 if(li!=lj&&ri!=rj){
    134 if(l[i]<r[j]&&l[i]+len[i]>r[j]-len[j]){
    135 Insert(lj,li); deg[li]++;
    136 Insert(ri,rj); deg[rj]++;
    137 }
    138 if(r[i]-len[i]<l[j]+len[j]&&r[i]>l[j]){
    139 Insert(rj,ri); deg[ri]++;
    140 Insert(li,lj); deg[lj]++;
    141 }
    142 }
    143 }
    144 }
    145
    146 topo();
    147 puts("YES");
    148 for(int i=0;i<(n<<1);i++){
    149 if(col[blg[i]]==R){
    150 if(i&1){
    151 int ti=i>>1;
    152 int lh=(r[ti]-len[ti])/60,lm=(r[ti]-len[ti])%60;
    153 int rh=r[ti]/60,rm=r[ti]%60;
    154 printf("%0.2d:%0.2d %0.2d:%0.2d\n",lh,lm,rh,rm);
    155 }else{
    156 int ti=i>>1;
    157 int lh=l[ti]/60,lm=l[ti]%60;
    158 int rh=(l[ti]+len[ti])/60,rm=(l[ti]+len[ti])%60;
    159 printf("%0.2d:%0.2d %0.2d:%0.2d\n",lh,lm,rh,rm);
    160 }
    161 }
    162 }
    163 }else puts("NO");
    164 }
    165 }

      

    POJ 3648 Wedding [中等]

    比较裸的2-sat求可行解的题,题意比较绕,就是说新娘在一边,新娘相对的一边不能存在不和谐的人,求新娘一边的人是那些,这样就要求新郎必须在另一边,所以就要加一条新娘到新郎的边以满足情况,最后输出被染成蓝色的点

    View Code
      1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 2005
    6
    7 struct Edge{
    8 int vtx,next;
    9 }E[999999];
    10 int head[N],size;
    11 int dfn[N],low[N],blg[N],step,scc;
    12 int stk[N],top;
    13 bool ins[N];
    14
    15 void Init(){
    16 memset(head,-1,sizeof(head));
    17 memset(dfn,-1,sizeof(dfn));
    18 memset(ins,false,sizeof(ins));
    19 step=size=0; top=-1;
    20 }
    21
    22 void Insert(int u,int v){
    23 E[size].vtx=v;
    24 E[size].next=head[u];
    25 head[u]=size++;
    26 }
    27
    28 void Tarjan(int u){
    29 stk[++top]=u; ins[u]=true;
    30 dfn[u]=low[u]=step++;
    31 for(int i=head[u];i!=-1;i=E[i].next){
    32 int v=E[i].vtx;
    33 if(dfn[v]==-1){
    34 Tarjan(v);
    35 low[u]=MIN(low[u],low[v]);
    36 }elseif(ins[v]){
    37 low[u]=MIN(low[u],dfn[v]);
    38 }
    39 }
    40 if(low[u]==dfn[u]){
    41 for(int v=-1;v!=u;top--){
    42 v=stk[top];
    43 ins[v]=false;
    44 blg[v]=scc;
    45 }
    46 scc++;
    47 }
    48 }
    49
    50 constint W=0;
    51 constint R=1;
    52 constint B=2;
    53 int deg[N],col[N],opp[N];
    54 int que[N],ss,ee;
    55
    56 void topo(){
    57 ss=ee=0;
    58 memset(col,W,sizeof(col));
    59 for(int i=0;i<scc;i++){
    60 if(!deg[i]) que[ee++]=i;
    61 }
    62 while(ss<ee){
    63 int u=que[ss++];
    64 if(col[u]) continue;
    65 col[u]=R; col[opp[u]]=B;
    66 for(int i=head[u];i!=-1;i=E[i].next){
    67 int v=E[i].vtx; deg[v]--;
    68 if(!deg[v]) que[ee++]=v;
    69 }
    70 }
    71 }
    72
    73 int l[N],r[N];
    74 int main(){
    75 int n,m;
    76 while(scanf("%d%d",&n,&m),n||m){
    77 n<<=1;
    78 Init(); scc=0;
    79 Insert(1,0);
    80 for(int i=0;i<m;i++){
    81 char cl,cr;
    82 scanf("%d%c%d%c",&l[i],&cl,&r[i],&cr);
    83 l[i]<<=1; r[i]<<=1;
    84 if(cl=='w') l[i]^=1;
    85 if(cr=='w') r[i]^=1;
    86 Insert(l[i],r[i]^1);
    87 Insert(r[i],l[i]^1);
    88 }
    89 for(int i=0;i<n;i++){
    90 if(dfn[i]==-1) Tarjan(i);
    91 }
    92 bool flag=true;
    93 for(int i=0;i<(n>>1);i++){
    94 opp[blg[i<<1]]=blg[i<<1|1];
    95 opp[blg[i<<1|1]]=blg[i<<1];
    96 if(blg[i<<1]==blg[i<<1|1]){
    97 flag=false; break;
    98 }
    99 }
    100 if(flag){
    101 Init();
    102 memset(deg,0,sizeof(deg));
    103 Insert(blg[0],blg[1]);
    104 deg[blg[1]]++;
    105 for(int i=0;i<m;i++){
    106 int rl=blg[l[i]];
    107 int rr=blg[r[i]];
    108 if(rl==opp[rr]||rr==opp[rl]) continue;
    109 Insert(opp[rl],rr);
    110 Insert(opp[rr],rl);
    111 deg[rr]++;
    112 deg[rl]++;
    113 }
    114
    115 topo();
    116 for(int i=2;i<n;i++){
    117 if(col[blg[i]]==B){
    118 if(i>3) putchar('');
    119 if(i&1) printf("%dw",i>>1);
    120 else printf("%dh",i>>1);
    121 }
    122 }puts("");
    123 }else puts("bad luck");
    124 }
    125 }

      

      

    更新:

    SRM464 div1 550题

    在MatRush大神的博客里看到这题,就去做了下,比较裸的2-sat,bomb game那题的圆这里是方形而已,很快敲完并过了test,正在得意时去看各大神代码才发现自己又水了,因为只有100个点,直接floyd做一遍然后判连通就行了,看来离真正懂2-sat还差的远啊~~

        

    POJ 3905 Perfect Election

    北大的第八道2-sat,和前面几题差不多,按照题目要求建图就好了

    View Code
     1 #include<cstdio>
    
    2 #include<cstring>
    3 usingnamespace std;
    4 #define MIN(x,y) (x>y?y:x)
    5 #define N 2005
    6 #define M 2000005
    7
    8 struct Edge{
    9 int vtx,next;
    10 }E[M];
    11 int head[N],size;
    12 int dfn[N],low[N],blg[N],step,scc;
    13 int stk[N],top;
    14 bool ins[N];
    15
    16 void Init(){
    17 memset(head,-1,sizeof(head));
    18 memset(dfn,-1,sizeof(dfn));
    19 memset(ins,false,sizeof(ins));
    20 size=step=scc=0; top=-1;
    21 }
    22
    23 void Insert(int u,int v){
    24 E[size].vtx=v;
    25 E[size].next=head[u];
    26 head[u]=size++;
    27 }
    28
    29 void Tarjan(int u){
    30 stk[++top]=u; ins[u]=true;
    31 dfn[u]=low[u]=step++;
    32 for(int i=head[u];i!=-1;i=E[i].next){
    33 int v=E[i].vtx;
    34 if(dfn[v]==-1){
    35 Tarjan(v);
    36 low[u]=MIN(low[u],low[v]);
    37 }elseif(ins[v]){
    38 low[u]=MIN(low[u],dfn[v]);
    39 }
    40 }
    41 if(low[u]==dfn[u]){
    42 for(int v=-1;v!=u;top--){
    43 v=stk[top];
    44 ins[v]=false;
    45 blg[v]=scc;
    46 }
    47 scc++;
    48 }
    49 }
    50
    51 int main(){
    52 int n,m;
    53 while(~scanf("%d%d",&n,&m)){
    54 Init();
    55 for(int i=0;i<m;i++){
    56 int u,v;
    57 scanf("%d%d",&u,&v);
    58 if(u>0&&v>0){
    59 Insert((u-1)<<1|1,(v-1)<<1);
    60 Insert((v-1)<<1|1,(u-1)<<1);
    61 }elseif(u>0){
    62 Insert((u-1)<<1|1,(-v-1)<<1|1);
    63 Insert((-v-1)<<1,(u-1)<<1);
    64 }elseif(v>0){
    65 Insert((-u-1)<<1,(v-1)<<1);
    66 Insert((v-1)<<1|1,(-u-1)<<1|1);
    67 }else{
    68 Insert((-u-1)<<1,(-v-1)<<1|1);
    69 Insert((-v-1)<<1,(-u-1)<<1|1);
    70 }
    71 }
    72 for(int i=0;i<(n<<1);i++){
    73 if(dfn[i]==-1) Tarjan(i);
    74 }
    75 bool flag=true;
    76 for(int i=0;i<n;i++){
    77 if(blg[i<<1]==blg[i<<1|1]){
    78 flag=false;
    79 break;
    80 }
    81 }
    82 puts(flag?"1":"0");
    83 }
    84 }

      

    HDU 4115 Eliminate the Conflict

    题解这里

    以上转自http://www.cnblogs.com/ambition/archive/2011/07/30/2-sat.html

    hdu4115

    按照我自己的建图方式,,依照2-sat 的方式,转换为3-sat

    View Code
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    using namespace std;
    
    const int N = 10000*3+10;
    vector<int> g[N];
    stack<int> st;
    
    int n,num,index,dfn[N],low[N],f[N];
    bool instack[N],vis[N];
    int B[N];
    void tarjan(int u)
    {
        vis[u]=true;
        st.push(u);
        instack[u]=true;
        dfn[u]=low[u]=index++;
        int v;
        for(int i=0;i<g[u].size();i++)
        {
            v=g[u][i];
            if(!vis[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(instack[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            do
            {
                v=st.top();
                st.pop();
                instack[v]=false;
                f[v]=num;
            }while(v!=u);
            num++;
        }
    }
    
    bool solve()
    {
        memset(vis,false,sizeof(vis));
        memset(instack,false,sizeof(instack));
        num=index=0;
    
        for(int i=0;i<3*n;i++)
            if(!vis[i])
                tarjan(i);
        for(int i=0;i<n;i++)
            if(f[i*3]==f[i*3+1] || f[i*3]==f[i*3+2] || f[i*3+1]==f[i*3+2])
                return false; 
        return true;
    }
    int main()
    {
        int T,cas=0,m;
        int a,b,k;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d %d",&n,&m);
            for(int i=0;i<n;i++)
            {
                scanf("%d",&B[i]);
                --B[i];
            }
            for(int i=0;i<3*n;i++)
                g[i].clear();
            for(int i=0;i<m;i++)
            {
                scanf("%d %d %d",&a,&b,&k);
                --a;--b;
                if(B[a]==B[b] && !k) continue;
                int t1=B[a];
                int t2=(B[a]+1)%3;
                int t3=B[b];
                int t4=(B[b]+1)%3;
                if(k)
                {
                    if(t1==t3)
                    {
                        g[a*3+t1].push_back(b*3+t4);
                        g[b*3+t3].push_back(a*3+t2);
                    }
                    if(t1==t4)
                    {
                        g[a*3+t1].push_back(b*3+t3);
                        g[b*3+t4].push_back(a*3+t2);
                    }
                    if(t2==t3)
                    {
                        g[a*3+t2].push_back(b*3+t4);
                        g[b*3+t3].push_back(a*3+t1);
                    }
                    if(t2==t4)
                    {
                        g[a*3+t2].push_back(b*3+t3);
                        g[b*3+t4].push_back(a*3+t1);
                    }
                }
                else {
                    if(t1==t3)
                    {
                        g[3*a+t2].push_back(3*a+t1);
                        g[3*a+(B[a]+2)%3].push_back(3*a+t1);
                        g[3*b+t4].push_back(3*b+t3);
                        g[3*b+(B[b]+2)%3].push_back(3*b+t3);
                    }
                    else if(t1==t4)
                    {
                        g[3*a+t2].push_back(3*a+t1);
                        g[3*a+(B[a]+2)%3].push_back(3*a+t1);
                        g[3*b+t3].push_back(3*b+t4);
                        g[3*b+(B[b]+2)%3].push_back(3*b+t4);
                    }
                    else if(t2==t3)
                    {
                        g[3*a+t1].push_back(3*a+t2);
                        g[3*a+(B[a]+2)%3].push_back(3*a+t2);
                        g[3*b+t4].push_back(3*b+t3);
                        g[3*b+(B[b]+2)%3].push_back(3*b+t3);
                    }
                    else if(t2==t4)
                    {
                        g[3*a+t1].push_back(3*a+t2);
                        g[3*a+(B[a]+2)%3].push_back(3*a+t2);
                        g[3*b+t3].push_back(3*b+t4);
                        g[3*b+(B[b]+2)%3].push_back(3*b+t4);
                    }
                }
            }
            printf("Case #%d: ",++cas);
            if(solve())
                puts("yes");
            else puts("no");
        }
        return 0;
    }
  • 相关阅读:
    Web测试与App测试的区别-总结篇
    Shell之基本用法
    Samba服务部署
    Linux基础(3)
    linux基础(2)
    linux基础(2)
    Linux基础(1)
    网络基础及网络协议
    操作系统简介
    计算机基础重要性
  • 原文地址:https://www.cnblogs.com/nanke/p/2630207.html
Copyright © 2020-2023  润新知