bzoj4945 [Noi2017]游戏(2-sat+枚举)

如果没有x那就是很标准的2-sat模型。
每个点两种选择,上第一种车或第二种,要求i,oi,j,oi就建边i,oi->j,oj,建边j,oj^!->i,oi^1

那对于x怎么办呢?这是3-sat呀qaq还好x的很少,我们可以枚举他为不能上A或不能上B(可以发现,不用枚举不能上C,因为前面的两种情况已经枚举全了)。
复杂度 O(2d(n+m)) O ( 2 d ( n + m ) )

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,D,pos[10],m,tot=-1,h[N<<1],num,id[N][2],dfn[N<<1],low[N<<1],dfnum,scc,bel[N<<1];
char s[N],op[2];bool flag=0,inq[N<<1];
int du[N<<1],col[N<<1],opp[N<<1];
struct node{
    int x,opx,y,opy;
}ev[100010];
struct edge{
    int fr,to,next;
}data[200010];
inline void add(int x,int y){
    data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].fr=x;
}
inline char idto(int x,int op){
    if(s[x]=='a') return 'A'+op+1;
    if(s[x]=='b') return op?'C':'A';
    return 'A'+op;
}
inline int toid(int x,int op){
    if(s[x]=='a') return op-1;
    if(s[x]=='b') return op?1:0;
    return op;
}stack<int>qq;
inline void tarjan(int x){
    dfn[x]=low[x]=++dfnum;qq.push(x);inq[x]=1;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(inq[y]) low[x]=min(low[x],dfn[y]);
    }if(dfn[x]==low[x]){
        ++scc;while(1){
            int y=qq.top();qq.pop();inq[y]=0;
            bel[y]=scc;if(y==x) break;
        }
    }
}
inline void solve(){
    memset(h,0,sizeof(h));num=0;
    memset(dfn,0,sizeof(dfn));scc=0;dfnum=0;
    for(int i=1;i<=m;++i){
        int x=ev[i].x,y=ev[i].y;
        if(ev[i].opx==s[x]-'a') continue;
        int opx=toid(x,ev[i].opx),opy=toid(y,ev[i].opy);
        if(ev[i].opy==s[y]-'a') add(id[x][opx],id[x][opx^1]);
        else add(id[x][opx],id[y][opy]),add(id[y][opy^1],id[x][opx^1]);
    }for(int i=0;i<=tot;++i) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;++i){
        if(bel[id[i][0]]==bel[id[i][1]]) return;opp[bel[id[i][0]]]=bel[id[i][1]];
        opp[bel[id[i][1]]]=bel[id[i][0]];
    }flag=1;
}
void dfs(int x){
    if(x==D+1){solve();return;}
    s[pos[x]]='a';dfs(x+1);if(flag) return;
    s[pos[x]]='b';dfs(x+1);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();D=read();scanf("%s",s+1);m=read();
    for(int i=1;i<=n;++i) if(s[i]=='x') pos[++pos[0]]=i;
    for(int i=1;i<=n;++i) id[i][0]=++tot,id[i][1]=++tot;
    for(int i=1;i<=m;++i){
        ev[i].x=read();scanf("%s",op+1);ev[i].opx=op[1]-'A';
        ev[i].y=read();scanf("%s",op+1);ev[i].opy=op[1]-'A';
    }dfs(1);if(!flag){puts("-1");return 0;}
    int num1=num;memset(h,0,sizeof(h));num=0;
    for(int i=1;i<=num1;++i){
        int x=data[i].fr,y=data[i].to;
        if(bel[x]!=bel[y]) add(bel[y],bel[x]),du[bel[x]]++;
    }queue<int>q;
    for(int i=1;i<=scc;++i) if(!du[i]) q.push(i);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=data[i].next){
            int y=data[i].to;if(--du[y]==0) q.push(y); 
        }if(col[x]) continue;col[x]=1;col[opp[x]]=2;
    }for(int i=1;i<=n;++i){
        if(col[bel[id[i][0]]]==1) putchar(idto(i,0));
        else putchar(idto(i,1));
    }return 0;
}

6.29upd:uoj上需要卡时一下才能过qaq

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 50010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,d=0,m,id[N][3],pos[10],tot,h[N<<1],num,dfn[N<<1],low[N<<1],dfnum,scc,bel[N<<1],du[N<<1],opp[N<<1];
bool inq[N<<1];int vis[N<<1];
char s[N];
struct Edge{
    int x,x1,y,y1;
}e[N<<1];
struct edge{
    int to,next,fr;
}data[N<<2];
inline void add(int x,int y){
    data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].fr=x;
}
stack<int>qq;
inline void tarjan(int x){
    dfn[x]=low[x]=++dfnum;qq.push(x);inq[x]=1;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(inq[y]) low[x]=min(low[x],dfn[y]);
    }if(low[x]==dfn[x]){
        ++scc;while(1){
            int y=qq.top();qq.pop();inq[y]=0;
            bel[y]=scc;if(y==x) break;
        }
    }
}
inline bool solve(){
    tot=1;num=0;memset(h,0,sizeof(h));memset(dfn,0,sizeof(dfn));dfnum=0;scc=0;memset(du,0,sizeof(du));memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;++i)
        for(int j=0;j<3;++j)
            if(j!=s[i]-'a') id[i][j]=++tot;
    for(int i=1;i<=m;++i){
        if(e[i].x1==s[e[i].x]-'a') continue;
        if(e[i].y1==s[e[i].y]-'a'){add(id[e[i].x][e[i].x1],id[e[i].x][e[i].x1]^1);continue;}
        add(id[e[i].x][e[i].x1],id[e[i].y][e[i].y1]);
        add(id[e[i].y][e[i].y1]^1,id[e[i].x][e[i].x1]^1);
    }for(int i=2;i<=tot;++i) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;++i){
        if(bel[i<<1]==bel[i<<1|1]) return 0;
        opp[bel[i<<1]]=bel[i<<1|1];opp[bel[i<<1|1]]=bel[i<<1];
    }int numm=num;num=0;memset(h,0,sizeof(h));
    for(int i=1;i<=numm;++i){
        int x=data[i].fr,y=data[i].to;
        if(bel[x]!=bel[y]) add(bel[y],bel[x]),du[bel[x]]++;
    }queue<int>q;
    for(int i=1;i<=scc;++i) if(!du[i]) q.push(i);
    while(!q.empty()){
        int x=q.front();q.pop();if(vis[x]) continue;
        vis[x]=1;vis[opp[x]]=2;
        for(int i=h[x];i;i=data[i].next){
            int y=data[i].to;if(--du[y]==0) q.push(y);
        }
    }for(int i=1;i<=n;++i)
        for(int j=0;j<3;++j){
            if(j==s[i]-'a') continue;
            if(vis[bel[id[i][j]]]==1) putchar('A'+j);
        }puts("");return 1;
}
inline bool dfs(int lev){
    if(lev>d) return solve();
    if((double)clock()/CLOCKS_PER_SEC>0.8){puts("-1");exit(0);}
    s[pos[lev]]='a';if(dfs(lev+1)) return 1;
    s[pos[lev]]='b';if(dfs(lev+1)) return 1;
    return 0;
}
int main(){
//  freopen("game2.in","r",stdin);
    n=read();read();scanf("%s",s+1);
    for(int i=1;i<=n;++i) if(s[i]=='x') pos[++d]=i;
    m=read();for(int i=1;i<=m;++i){
        e[i].x=read();char op[2];scanf("%s",op);e[i].x1=op[0]-'A';
        e[i].y=read();scanf("%s",op);e[i].y1=op[0]-'A';
    }if(!dfs(1)) puts("-1");
    return 0;
}       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值