zoukankan      html  css  js  c++  java
  • BZOJ 4945 UOJ #317 NOI2017 游戏 2-SAT 拓扑排序

    http://uoj.ac/problem/317

    https://www.lydsy.com/JudgeOnline/problem.php?id=4945

    我现在的程序uoj的额外数据通过不了,bzoj应该是原版数据所以可以过??

    x不超过8个所以2^8枚举一下就可以了。每个可以选择的状态实际上只有两个所以还是2-SAT。

    2-SAT的图需要满足对偶性,所以逆否连边很有用。

    我之前不会这种问题怎么输出方案,输出方案的方法就是tarjan之后topsort,再对每个强连通分量决定选还是不选(把矛盾的都不选,和矛盾相反的选,具体看代码里的dfs1函数)。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<iostream>
      6 using namespace std;
      7 #define LL long long
      8 const int maxn=300010;
      9 int n,d,fla=0,m;
     10 char ch[maxn],ch1[2],ch2[2],ans[maxn];
     11 int pos[10]={};
     12 struct node{
     13     int id1,x,id2,y;
     14 }a[maxn];
     15 struct nod{
     16     int y,next;
     17 };nod e[maxn],e1[maxn];
     18 int head[maxn]={},head1[maxn]={},tot=0,tot1=0;
     19 int low[maxn]={},dfn[maxn]={},sta[maxn]={},bel[maxn]={},cnt=0,tai=0,tly=0;
     20 int de[maxn]={},op[maxn]={}; bool vis[maxn]={};
     21 int ob[maxn]={},dd[maxn]={},co[maxn]={};
     22 int q[maxn]={},s=0,t=0;
     23 inline void init(int x,int y){
     24     e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
     25 }
     26 inline void init1(int x,int y){
     27     e1[++tot1].y=y;e1[tot1].next=head1[x];head1[x]=tot1;
     28 }
     29 void tarjan(int x){
     30     sta[++tai]=x;low[x]=dfn[x]=++cnt;vis[x]=1;
     31     for(int i=head[x];i;i=e[i].next){
     32         if(!dfn[e[i].y]){
     33             tarjan(e[i].y);
     34             low[x]=min(low[x],low[e[i].y]);
     35         }
     36         else if(vis[e[i].y]) low[x]=min(low[x],dfn[e[i].y]);
     37     }
     38     if(low[x]==dfn[x]){
     39         int w;tly++;
     40         do{
     41             w=sta[tai--];
     42             bel[w]=tly;vis[w]=0;
     43         }while(w!=x);
     44     }
     45 }
     46 void Check(){
     47     memset(dfn,0,sizeof(dfn));
     48     memset(head,0,sizeof(head));
     49     tot=0;cnt=0;tly=0;
     50     int aa,bb,cc;
     51     for(int i=1;i<=n;i++){
     52         aa=(ch[i]-'a')*n+i;bb=(aa+n-1)%(3*n)+1;cc=(bb+n-1)%(3*n)+1;
     53         de[aa]=1;de[bb]=0;de[cc]=0;
     54         op[bb]=cc;op[cc]=bb;
     55     }
     56     for(int i=1;i<=m;i++){
     57         aa=a[i].x*n+a[i].id1;bb=a[i].y*n+a[i].id2;
     58         if(aa==bb||de[aa])continue;
     59         if(a[i].id1==a[i].id2||de[bb]){
     60             init(aa,op[aa]);//aa一定到op[aa]即表明aa不能选
     61         }
     62         else{init(op[bb],op[aa]);init(aa,bb);}//图要对偶所以aa连bb逆否也连一下
     63     }
     64     for(int i=1;i<=3*n;i++){
     65         if(de[i]||dfn[i])continue;
     66         tarjan(i);
     67     }
     68     for(int i=1;i<=3*n;i++){
     69         if(de[i])continue;
     70         if(bel[i]==bel[op[i]])return;
     71         ob[bel[i]]=bel[op[i]];ob[bel[op[i]]]=bel[i];
     72     }
     73     fla=1;
     74 }
     75 void dfs(int x){
     76     if(x==d+1){
     77         Check();return;
     78     }
     79     ch[pos[x]]='a';dfs(x+1);
     80     if(fla)return;
     81     ch[pos[x]]='b';dfs(x+1);
     82 }
     83 void dfs1(int x){
     84     if(co[x]!=-1)return;
     85     co[x]=0;co[ob[x]]=1;
     86     for(int i=head1[x];i;i=e1[i].next)dfs1(e1[i].y);
     87 }
     88 int main(){
     89     scanf("%d%d%s%d",&n,&d,ch+1,&m);
     90     for(int i=1;i<=n;i++)if(ch[i]=='x')pos[++pos[0]]=i;
     91     for(int i=1;i<=m;i++){ 
     92         scanf("%d%s%d%s",&a[i].id1,ch1,&a[i].id2,ch2);
     93         a[i].x=ch1[0]-'A';a[i].y=ch2[0]-'A';
     94     }
     95     dfs(1);
     96     if(!fla){
     97         printf("-1
    ");return 0;
     98     }
     99     memset(co,-1,sizeof(co));
    100     for(int i=1;i<=3*n;i++){//强连通分量缩点后拓扑序
    101         if(de[i])continue;
    102         for(int j=head[i];j;j=e[j].next)
    103             if(bel[e[j].y]!=bel[i]){init1(bel[e[j].y],bel[i]);++dd[bel[i]];}
    104     }
    105     for(int i=1;i<=tly;i++)if(!dd[i])q[++t]=i;
    106     while(s<t){
    107         int x=q[++s];
    108         for(int i=head1[x];i;i=e1[i].next){
    109             --dd[e1[i].y];
    110             if(!dd[e1[i].y])q[++t]=e1[i].y;
    111         }
    112         if(co[x]!=-1)continue;
    113         dfs1(ob[x]);
    114     }
    115     for(int i=1;i<=3*n;i++){if((!de[i])&&co[bel[i]]==1)ans[(i-1)%n]='A'+(i-1)/n;}
    116     printf("%s",ans);
    117     return 0;
    118 }
    View Code

  • 相关阅读:
    TCP源码—连接建立
    TCP系列02—连接管理—1、三次握手与四次挥手
    TCP系列01—概述及协议头格式
    ubuntu软件管理apt与dpkg
    318. Maximum Product of Word Lengths
    317. Shortest Distance from All Buildings
    316. Remove Duplicate Letters
    315. Count of Smaller Numbers After Self
    314. Binary Tree Vertical Order Traversal
    313. Super Ugly Number
  • 原文地址:https://www.cnblogs.com/137shoebills/p/9099197.html
Copyright © 2011-2022 走看看