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\n");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

 

posted @ 2018-05-28 11:24  鲸头鹳  阅读(184)  评论(0编辑  收藏  举报