[BZOJ4945][Noi2017]游戏 2-sat

对于所有的x,我们枚举他的地图类型,事实上我们只需要枚举前两种地形就可以覆盖所有的情况。

之后就变成了裸的2-sat问题。

对于一个限制,我们分类讨论:

1.h[u]不可选,跳过

2.h[v]不可选,则h[v]也不可选,将u与u‘连边,表示u不可选。

3.否则从u向v连边表示选u就必须选v,从u’向v‘连边表示选v'就必须选u’(逆否命题)。

tarjan缩点判断可行性。

输出方案按照缩点编号选择编号小的点输出即可(逆序拓扑序)。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<algorithm>
  7 #define maxn 400005
  8 using namespace std;
  9 inline int read() {
 10     int x=0,f=1;char ch=getchar();
 11     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
 12     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
 13     return x*f;
 14 }
 15 struct Edge {int to,nxt;}e[maxn*2];
 16 int head[maxn],cnt;
 17 void add(int u,int v) {e[cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt++;}
 18 struct Ask {int u,v;char a[10],b[10];}q[maxn];
 19 int n,d,pos[maxn],m;
 20 char s[maxn],cs[maxn];
 21 bool flag=0;
 22 int dfn[maxn],low[maxn],tot,bel[maxn],par[maxn],l[maxn],r[maxn],sta[maxn],top,scc;
 23 bool vis[maxn],inq[maxn];
 24 void init() {
 25     memset(head,-1,sizeof(head));cnt=0;
 26     memset(dfn,0,sizeof(dfn));
 27     memset(low,0,sizeof(low));
 28     memset(bel,0,sizeof(bel));tot=0;scc=0;
 29     memset(vis,0,sizeof(vis));
 30     memset(inq,0,sizeof(inq));
 31 }
 32 void tarjan(int x) {
 33     dfn[x]=low[x]=++tot;sta[++top]=x;inq[x]=1;
 34     for(int i=head[x];i>=0;i=e[i].nxt) {
 35         int to=e[i].to;
 36         if(!dfn[to]) {
 37             tarjan(to);
 38             low[x]=min(low[x],low[to]);
 39         }
 40         else if(inq[to]) {low[x]=min(low[x],dfn[to]);}
 41     }
 42     if(dfn[x]==low[x]) {
 43         scc++;
 44         while(1) {
 45             inq[sta[top]]=0;
 46             bel[sta[top--]]=scc;
 47             if(sta[top+1]==x) break;
 48         }
 49     }
 50 }
 51 int que[maxn],fro,tail,in[maxn];
 52 void work() {
 53     init();
 54     for(int i=1;i<=n;i++) {
 55         int ttmp=0;
 56         if(s[i]=='x') {s[i]=cs[i];ttmp=1;}
 57         if(s[i]=='a') {l[i]=i+n,r[i]=i+n+n;}
 58         if(s[i]=='b') {l[i]=i,r[i]=i+n+n;}
 59         if(s[i]=='c') {l[i]=i,r[i]=i+n;}
 60         if(ttmp==1) s[i]='x';
 61         par[l[i]]=r[i];par[r[i]]=l[i];vis[r[i]]=vis[l[i]]=1;
 62     }
 63     int ql,qr;
 64     for(int i=1;i<=m;i++) {
 65         if(q[i].a[1]=='A') ql=q[i].u;
 66         else if(q[i].a[1]=='B') ql=q[i].u+n;
 67         else ql=q[i].u+n+n;
 68         if(q[i].b[1]=='A') qr=q[i].v;
 69         else if(q[i].b[1]=='B') qr=q[i].v+n;
 70         else qr=q[i].v+n+n;
 71         if(ql==qr) continue;
 72         if(!vis[ql]) continue;
 73         if(!vis[qr]) {
 74             add(ql,par[ql]);
 75             continue;
 76         }
 77         add(ql,qr);add(par[qr],par[ql]);
 78     }
 79     for(int i=1;i<=n+n+n;i++) {if(vis[i]&&!dfn[i]) tarjan(i);}
 80     for(int i=1;i<=n+n+n;i++) {
 81         if(!vis[i]) continue;
 82         if(bel[i]==bel[par[i]]) return;
 83     }
 84     flag=1;
 85     for(int i=1;i<=n;i++) {
 86         int out=0;
 87         if(bel[l[i]]<bel[r[i]]) out=l[i];
 88         else out=r[i];
 89         if(out==i) printf("A");
 90         else if(out==i+n) printf("B");
 91         else printf("C");
 92     }
 93 }
 94 void dfs(int x) {
 95     if(x==d+1) {
 96         work();
 97         if(flag) exit(0);
 98         return;
 99     }
100     cs[pos[x]]='a';dfs(x+1);
101     cs[pos[x]]='b';dfs(x+1);
102 }
103 int main() {
104     n=read(),d=read();
105     scanf("%s",s+1);
106     for(int i=1;i<=n;i++) {if(s[i]=='x') pos[++pos[0]]=i;}
107     m=read();
108     for(int i=1;i<=m;i++) {q[i].u=read();scanf("%s",q[i].a+1);q[i].v=read();scanf("%s",q[i].b+1);}
109     dfs(1);printf("-1\n");
110 } 
View Code

 

posted @ 2018-12-21 10:28  wls001  阅读(177)  评论(0编辑  收藏  举报