[Noi2017]游戏

2-SAT的题啦
考虑到x很小,我们只需要暴力枚举x是什么就好了,然后每个点就两种状态,2-SAT模型啦!
总的复杂度 O(3dn)
然后呢,建图的时候,将一些边建好,剩下的与x有关的到时候再建,可以减少很多复杂度。。要不可能会超。。但是uoj的数据一般般,不这么做也行,然后bzoj根本就没有spj

然后我这个写法不是哪里出了一点点小问题,uoj95分,还有一个点WA了。。看了半天,很绝望。。
我又不想写spj,于是对拍也不大好。。就这样吧,估计也就是一点点细节问题。。
就这样吧,但我觉得方法是没有问题啊,大家可以借鉴哈!但抄代码就别了。。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=50005*2;
const int M=100005*2;
int n,d,m;
char ss[N];
struct qq
{
    int i,hi;
    int j,hj;
}s[M];
int read ()
{
    char ch=getchar();int x=0;
    while (ch<'0'||ch>'9')  ch=getchar();
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x;
}
int read1 ()
{
    char ch=getchar();
    while (ch!='A'&&ch!='B'&&ch!='C') ch=getchar();
    return ch-'A'+1;
}
struct qy
{
    int x,y,last;
}e[M];int num,last[N];
void init (int x,int y)
{
    num++;
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
int a[N];
int P (int x,int y)//在x这个地方填y的编号 
{
    if (a[x]==y) return -1;
    int cnt=0;
    for (int u=1;u<=3;u++)
    {
        if (a[x]==u) continue;
        if (u==y) break;
        cnt++;
    }
    return cnt*n+x;
}
bool tf=false;
int dfn[N],low[N],belong[N],cnt,sta[N],lalal,shen;
bool in[N];
int mymin (int x,int y){return x<y?x:y;}
void dfss (int x)
{
    dfn[x]=low[x]=++lalal;
    sta[++cnt]=x;
    in[x]=true;
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (dfn[y]==-1)
        {
            dfss(y);
            low[x]=mymin(low[x],low[y]);
        }
        else if (in[y]) low[x]=mymin(dfn[y],low[x]);
    }
    if (low[x]==dfn[x])
    {
        shen++;
        int now;
        do
        {
            now=sta[cnt--];
            belong[now]=shen;
            in[now]=false;
        }while (now!=x);
    }
}
qy e1[M];int num1,last1[N];
int du[N];
void init1 (int x,int y)
{
    du[y]++;
    num1++;
    e1[num1].x=x;e1[num1].y=y;
    e1[num1].last=last1[x];
    last1[x]=num1;
}
void rebt ()
{
    num1=0;memset(last1,-1,sizeof(last1));
    for (int u=1;u<=2*n;u++)
        for (int i=last[u];i!=-1;i=e[i].last)
        {
            int y=e[i].y;
            if (belong[u]!=belong[y])
                init1(belong[y],belong[u]);
        }
}
int op[N];
int col[N];
void dfs1 (int x)
{
    if (col[x]!=0) return ;
    col[x]=2;
    for (int u=last1[x];u!=-1;u=e1[u].last)
    {
        int y=e1[u].y;
        dfs1(y);
    }
}
void topsort ()
{
    queue<int> q;
    for (int u=1;u<=shen;u++)
        if (du[u]==0) q.push(u);
    while (!q.empty())
    {
        int x=q.front();q.pop();
        //printf("%d",x);
        if (col[x]!=0) continue;
        col[x]=1;dfs1(op[x]);
        for (int u=last1[x];u!=-1;u=e1[u].last)
        {
            int y=e1[u].y;
            du[y]--;
            if (du[y]==0) q.push(y);
        }
    }
}
void print (int x,int y)
{
    //printf("%d %d %d\n",x,y,a[x]);
    int cnt=0;
    for (int u=1;u<=3;u++)
    {
        if (a[x]==u) continue;
        cnt++;
        if (cnt==y) 
        {
            printf("%c",u+'A'-1);
            break;
        }
    }
}
void check ()//当前这个序列有没有一个合法方案 
{
    num=0;memset(last,-1,sizeof(last));
    for (int u=1;u<=m;u++)
    {
        int x=P(s[u].i,s[u].hi),y=P(s[u].j,s[u].hj);
        if (x==-1) continue;
        if (y==-1) init(x,(x+n)%(2*n));
        else {init(x,y);init((y+n)%(2*n),(x+n)%(2*n));}
    }
    memset(dfn,-1,sizeof(dfn));
    memset(in,false,sizeof(in));
    shen=lalal=cnt=0;
    for (int u=1;u<=2*n;u++)
        if (dfn[u]==-1)
            dfss(u);
    for (int u=1;u<=n;u++)
        if (belong[u]==belong[u+n])
            return ;
/*  printf("%d %d\n",a[1],a[2]);
    for (int u=1;u<=m;u++)
    {
        int x=P(s[u].i,s[u].hi),y=P(s[u].j,s[u].hj);
    //  if (x==-1) continue;
        printf("YES:%d %d\n",x,y);
        /*if (y==-1) init(x,(x+n)%(2*n));
        init(x,y);
    }*/
//  for (int u=1;u<=num;u++) printf("%d %d\n",e[u].x,e[u].y); 
    tf=true;
    memset(du,0,sizeof(du));
    rebt();
    for (int u=1;u<=n;u++)
    {
        op[belong[u]]=  belong[u+n];
        op[belong[u+n]]=belong[u];
    }
    memset(col,0,sizeof(col));
    /*for (int u=1;u<=2*n;u++) printf("%d ",[u]);
    printf("\n");
    for (int u=1;u<=num1;u++) printf("%d %d\n",e1[u].x,e1[u].y);*/
    topsort();
//  for (int u=1;u<=2*n;u++) printf("%d ",col[u]);
    for (int u=1;u<=n;u++)
        if (col[belong[u]]==1)  print(u,1);
        else print(u,2);
}
void dfs (int x)//到哪一位了
{
    if (tf) return ;
    if (x>n) {check();return ;}
    if (ss[x]=='x')
    {
        a[x]=1;dfs(x+1);
        a[x]=2;dfs(x+1);
        a[x]=3;dfs(x+1);
    }
    else 
    {
        a[x]=ss[x]-'a'+1;
        dfs(x+1);
    }
}
int main()
{
    scanf("%d%d",&n,&d);
    scanf("%s",ss+1);
    scanf("%d",&m);
    for (int u=1;u<=m;u++)
    {
        s[u].i=read();s[u].hi=read1();
        s[u].j=read();s[u].hj=read1();
    }
    dfs(1);
    if (tf==false) printf("-1");
/*  if (tf) printf("YES\n");
    else printf("NO\n");*/
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值