(转)2-sat 专题
【2-sat】专题~
2-sat是一个逻辑性很强的算法,但是其套路比较固定,所以不是很热,题目很少,但也不乏AC后让人大呼爽快的好题,下面放出两篇极品论文还有几道题目的题解以供交流~~
2-sat学习:
对称性解决2-sat的ppt
赵爽的2-SAT解法浅析论文
强连通判是否存在解:
HDU 3062 Party [入门]
2-sat入门题,建图后求强连通判断是否有解即可
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 [基础]
把每队的两名队员当作一个整体,队长和队员为相对状态,建图求强连通即可
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 [基础]
判断两段是否相交,如果相交的话不能在同侧,在两侧为相对状态,建图求强连通
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 (两个数必须相同)
然后求强联通即可
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
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的情况很容易忘记考虑
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
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
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
二分能打开门的个数,强连通判解
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,然后就和上题一样了
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 [中等]
因为要求最小字典序解,所以就不能用强连通+拓扑排序的方法做了,直接用暴力的方法求出解即可,复杂度有点高啊
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求可行解了
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求可行解的题,题意比较绕,就是说新娘在一边,新娘相对的一边不能存在不和谐的人,求新娘一边的人是那些,这样就要求新郎必须在另一边,所以就要加一条新娘到新郎的边以满足情况,最后输出被染成蓝色的点
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,和前面几题差不多,按照题目要求建图就好了
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
#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; }
转载于:https://www.cnblogs.com/nanke/archive/2012/08/09/2630207.html
(转)2-sat 专题相关推荐
- $2019$ 暑期刷题记录 $2$(基本算法专题)
$ 2019 $ 暑期刷题记录 $ 2 $ (基本算法专题) $ by~~wch $ $ BZOJ~1958~Strange~Towers~of~Hanoi $ (动态规划,递推) 题目大意: 求有 ...
- JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)...
2019独角兽企业重金招聘Python工程师标准>>> 前提概要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外 ...
- 【Typescript专题】之类型进阶
[Typescript专题]之类型进阶 本篇文章是<Typescript 专题>第一篇,本篇文章主要聊一聊基本类型相关的扩展,毕竟随着文章的加深,我在阅读官方文档的时候经常会见到陌生的声明 ...
- SAPGUI 里 F1 功能键的用法专题讲解试读版
本专栏计划的文章数在 150 篇左右,到 2022年10月6日为止,目前已经更新了 56 篇,专栏完成度为 37.3% 笔者这套零基础快速学习 ABAP从 2021年4月10日写下第一篇文章以来,感谢 ...
- DDD专题案例二《领域层决策规则树服务设计》
前言介绍 在上一章节介绍了领域驱动设计的基本概念以及按照领域驱动设计的思想进行代码分层,但是仅仅只是从一个简单的分层结构上依然没法理解DDD以及如何去开发这样的微服务.另外往往按照这样分层后依然感觉和 ...
- 伍德里奇计量经济学导论之计算机操作题的R语言实现(一些重要专题)
引言 本章内容介绍了多元线性回归一些好玩且实用的专题: 改变自变量(因变量(对数自变量)当度量单位对因变量(自变量).系数.t值.F值等的影响 自变量和因变量标准化以后B系数的解释 对数-水平模型下, ...
- 【CVPR 2020】 旷视研究院提出SAT:优化解决半监督视频物体分割问题
IEEE国际计算机视觉与模式识别会议 CVPR 2020 (IEEE Conference on Computer Vision and Pattern Recognition) 将于 6 月 14- ...
- 图论专题-学习笔记:强连通分量
图论专题-学习笔记:强连通分量 一些 update 1. 前言 2. 定义 3. 求法 4. 应用 5. 总结 一些 update update on 2021/8/12:增加了对于 Kosaraju ...
- RTKLIB专题学习(十)—电离层改正
RTKLIB专题学习(十)-电离层改正 今天我们一起来学习下,RTKLIB中对电离层延迟改正的方法,并了解源码的相应模块,以便对原理有一定的了解 1.电离层延迟改正模型 由于存在大量的自由电子和正负离 ...
- RTKLIB专题学习(五)---单点定位实现进阶(一)
RTKLIB专题学习(五) 今天我们一起来了解一下,RTKLIB中的单点定位是如何实现的: 简单来说,就是最小二乘法,但是呢,RTKLIB里面的最小二乘实际上是加权最小二乘,因为他给出了观测值的权(实 ...
最新文章
- alter table add column多个字段_ElementUI表格el-table表头固定自适应高度解决方案
- 大数据、数据挖掘、机器学习与模式识别的关系
- python创建列表的语句_如何使用列表作为参数创建SELECT语句? - python
- [NHFrog]发布第三个版本_NHibernate嵌入式代码生成器
- regsvr32.exe是什么东西
- loadrunner中文件的操作
- was如何使用gzip_一文详解前端Node原生模块zlib,开启gzip压缩让页面响应速度更快...
- 如何设计软件类招聘考题
- 2021-2027全球与中国相控阵校准测试系统市场现状及未来发展趋势
- 杀人游戏规则总结(转自龙的天空)
- 防滑链行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
- python计算逆序的四位数_用C语言程序编写:输入一个四位整数(如1234),使其倒序输出(如4321),并求其各位之和。C语言 设计算法输入一个四位正...
- 视易服务器系统装,windows2000视易星云点歌数据服务器安装方法和步骤.docx
- java 枚举型 默认值,c# - 选择Enum类型的默认值而不必更改值
- 关于桌面发布时报错Failed Read-only file system
- Listen 1添加下载功能(列表下载方法)(v2.6)
- 浅谈电机,如何选择步进电机的型号?
- vs2005远程调试服务进程报R6025
- APS生产排产帮助面粉加工企业进行成本管控
- 人脸识别中的机器学习
热门文章
- leetcode —— 24. 两两交换链表中的节点
- leetcode —— 面试题 17.08. 马戏团人塔
- 数据结构——归并排序
- 对比关系生成模型(Comparative Relation Generative Model)
- 方法重载与重写,返回类型
- Golang的错误处理笔记
- 【QT 数据库专辑】【02】WIN7下搭建本地MYSQL数据库02 - 建立数据库的驱动程序-QT为例-完备版
- 请简述什么是spring的ioc和di_小编Spring是什么、spring容器、IOC和DI
- 客服机器人代码_电脑问题不会解决?小白智能客服来帮你!
- java学完jdk后学什么_学完了javase之后要学什么?