【BZOJ4945】游戏(NOI2017)-2-SAT+枚举

测试地址:游戏
做法:本题需要用到2-SAT+枚举。
看到大部分的地图都只能用两种赛车,赛车之间有一些依赖关系,这显然就是个2-SAT。而对于极少数的能用三种赛车的地图,我们枚举这些地图是不用A还是不用B,这样可以保证不漏掉方案,对每种情况做2-SAT即可,这样我们就解决了这一题,时间复杂度为O(2dn)
注意一个比较重要的处理是,建图时如果一条限制指向的点不能使用,就表示指向它的那个点也不能使用,而一个点不能取的限制体现在图里就是从这个点向同组的另一个点连边。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,d,X0[100010],Y0[100010],cnt=0,pos[10],tim,st[100010],top;
int dfn[100010],low[100010],first[200010],q[200010],tot;
int belong[100010],totscc,col[200010],in[200010]={0},Q[200010],QQ[200010];
char s[50010],X1[100010],Y1[100010];
bool vis[200010],inst[200010];
struct edge
{
    int v,next;
}e[2000010];

void insert(int a,int b)
{
    e[++tot].v=b;
    e[tot].next=first[a];
    first[a]=tot;
}

void tarjan(int v)
{
    vis[v]=inst[v]=1;
    dfn[v]=low[v]=++tim;
    st[++top]=v;
    int now=top;
    for(int i=first[v];i;i=e[i].next)
    {
        if (!vis[e[i].v])
        {
            tarjan(e[i].v);
            low[v]=min(low[v],low[e[i].v]);
        }
        else if (inst[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
    }
    if (low[v]==dfn[v])
    {
        totscc++;
        for(int i=top;i>=now;i--)
        {
            belong[st[i]]=totscc;
            inst[st[i]]=0;
        }
        top=now-1;
    }
}

bool check()
{
    for(int i=1;i<=n;i++)
        if (belong[i]==belong[n+i]) return 1;
    return 0;
}

void color(int x)
{
    int h=1,t=1;
    QQ[1]=x;
    while(h<=t)
    {
        int v=QQ[h++];
        if (vis[v]) continue;
        vis[v]=1;
        col[v]=0;
        for(int i=first[v];i;i=e[i].next)
            QQ[++t]=e[i].v;
    }
}

void solve()
{
    for(int i=1;i<=n;i++)
    {
        q[belong[i]]=belong[n+i];
        q[belong[n+i]]=belong[i];
    }
    for(int i=1;i<=(n<<1);i++)
    {
        for(int j=first[i];j;j=e[j].next)
            if (belong[i]!=belong[e[j].v])
            {
                insert(belong[e[j].v],belong[i]);
                in[belong[i]]++;
            }
    }
    int h=1,t=0;
    for(int i=(n<<1)+1;i<=totscc;i++)
        if (!in[i]) Q[++t]=i;
    while(h<=t)
    {
        int v=Q[h++];
        if (vis[v]) continue;
        vis[v]=1;
        col[v]=1;
        color(q[v]);
        for(int i=first[v];i;i=e[i].next)
        {
            in[e[i].v]--;
            if (!in[e[i].v]) Q[++t]=e[i].v;
        }
    }
    for(int i=1;i<=n;i++)
    {
        if (s[i]=='a') printf("%c",col[belong[i]]?'B':'C');
        if (s[i]=='b') printf("%c",col[belong[i]]?'A':'C');
        if (s[i]=='c') printf("%c",col[belong[i]]?'A':'B');
    }
}

int point(int x,char y)
{
    if (s[x]!='c') return y=='C';
    else return y=='B';
}

bool work()
{
    memset(first,0,sizeof(first));
    tot=0;
    for(int i=1;i<=m;i++)
    {
        if (s[X0[i]]==X1[i]-'A'+'a') continue;
        int px=point(X0[i],X1[i]);
        if (s[Y0[i]]==Y1[i]-'A'+'a')
        {
            insert(X0[i]+px*n,X0[i]+(!px)*n);
            continue;
        }
        int py=point(Y0[i],Y1[i]);
        insert(X0[i]+px*n,Y0[i]+py*n);
        insert(Y0[i]+(!py)*n,X0[i]+(!px)*n);
    }

    memset(vis,0,sizeof(vis));
    tim=top=0;
    totscc=n<<1;
    for(int i=1;i<=(n<<1);i++)
        if (!vis[i]) tarjan(i);
    if (check()) return 0;
    solve();
    return 1;
}

int main()
{
    scanf("%d%d",&n,&d);
    scanf("%s",s+1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
        scanf("%d %c%d %c",&X0[i],&X1[i],&Y0[i],&Y1[i]);

    bool flag=0;
    for(int i=1;i<=n;i++)
        if (s[i]=='x') pos[cnt++]=i;
    for(int i=0;i<(1<<d);i++)
    {
        for(int j=0;j<d;j++)
            s[pos[j]]=(i&(1<<j))?'a':'b';
        if (work()) {flag=1;break;}
    }
    if (!flag) printf("-1");

    return 0;
}
posted @ 2018-05-10 15:51  Maxwei_wzj  阅读(104)  评论(0编辑  收藏  举报