洛谷3852 BZOJ4945 NOI2017 游戏 2-SAT

题目链接
题意:有A、B、C、三种车,有n局游戏,每局游戏只能用一种车,每局有一种车不能用,也有一些局三种车都能用,但是三种车都能用的不超过8局,还有一些第I局用了某种车第j局就必须用某种车的限制,求一种合法的方案(若无合法方案,则输出-1)。

题解:
首先根据部分分的小提示,我们发现了三种车都可以的地图只会出现不超过8次,而且很多测试点是没有这种地图的。那么我们就先考虑没有这种地图应该怎么做。
我们发现,这道题是每一局都要从3种车中选一种,还有一些限制条件,然后再看到好几万的数据范围,一脸懵逼——3-SAT怎么可能可做?既然我们知道,3-SAT不可做,题目又出出来了,那么我们就应该去想办法把它转化成2-SAT问题。
对2-SAT有一定了解的话,这个转化可能并不难想到。我们发现,因为每一局都有一个限制,那么相当于每局都是二选一,那么我们可以把这两种情况看作2-SAT中的两个对立节点,这两者中必选一个。
然后我们处理那些限制,由于2-SAT的连边是根据“必须”关心来连的,即我们选了 i 就必须选 i 连到的所有点,所以用这个性质来处理限制。我们设 h x 为第 x 局假如选择的车,设 h y 为第 y 局限制必须选的车。如果第 x 局本身就不能选 h x 这种车,那么直接跳过这条限制。如果第 x 局有 h x 这种车可选,但是第 y 局本身不能选 h y 这种车,那么意味着如果第 x 局选了 h x ,那么第 y 局就要选 h y ,但是这样是不可行的,那么我们就必须不选 h x ,而去选它的对立节点,所以这种情况就从 h x 向它的对立节点连边。如果两种本身都在该局可选,那么我们就从 x y 连边,由于2-SAT要用逆否命题保证对称性(我是这么理解的,如果不对敬请斧正),所以我们还有再从 y 的对立节点向 x 的对立节点连边即可。这样图就建好了,用2-SAT模板就能求出答案了。
2-SAT输出方案是缩点、判完有解之后建缩后的点的反图,进行拓扑排序,如果点 x 所在的连通块的拓扑序在 x 之后,那么用第一个点,否则用第二个点。但是由于tatrjan的求强连通分量的过程中连通块的编号就是按拓扑排序逆序给出的(不是非常明白),所以只需要比较 x x 所在的连通块的编号即可完成判断(可以理解为卡了一波常数?)。
那么这样,对于没有三种车都可以选的局的情况我们就做完了。接下来就该考虑如何处理三种车可以用的局。
由于我们发现这样的局很少,所以我们考虑暴力处理,由刚才的做法我们得到启发,假如一个局有了一种车是不能用的限制,我们就会做了,那么我们就枚举每局以及依次限制A车、B车、C车,每次建图跑2-SAT,这样我们就得到了一个 O ( 3 8 ( m + n ) ) 的做法,(似乎是能过90分),但是还是过不了!其实我们要做的是让这些没有限制的局也从A、B、C中选一个,从而形成合法解,那么其实对于每一个无限制的局,前两次的枚举限制无论是限制不能选哪两种车,都已经提供了3种可选的车。具体点解释就是,假如前两次我们分别现在不能选A车、不能选B车,那么第一次B、C车可以选,第二次A、C车可以选,三种车已经都有了被选择的机会,所以不需要再去枚举第三次了。于是我们就得到了一个 O ( 2 8 ( m + n ) ) 的做法,就可以过掉本题了。
思路想出来之后代码里还是有些细节的,写错细节而丢分还是很难受的。这个题我的代码写得很不简练。
PS:感叹两句,好像好久没写博客了,暑假过得真快啊。暑假里果然是颓废,写的题看了看也没什么值得记的。最近学了一下2-SAT,但是感觉理解得并不深刻,所以没有写学习笔记。一些比较简单的2-SAT没有什么值得记的地方,所以就很久没有写博客了。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,d,m,hed[100010],cnt,book[10],ji,u[300010],v[300010],ct;
int dfn[100010],low[100010],vis[100010],sta[100010],tp,kuai[100010],pd,shu,tot,pan;
char s[50010],cur[500010][2];
struct node
{
    int to,next;
}a[1000100];
struct limit
{
    int x,y;
    char hx,hy;
}b[100010];
inline void add(int from,int to)
{
    a[++cnt].to=to;
    a[cnt].next=hed[from];
    hed[from]=cnt;
}
inline void tarjan(int x)
{
    sta[++tp]=x;
    vis[x]=1;
    dfn[x]=low[x]=++shu;
    for(int i=hed[x];i;i=a[i].next)
    {
        int y=a[i].to;
        if(!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])
        low[x]=min(low[x],low[y]);
    }
    if(dfn[x]==low[x])
    {
        ++tot;
        while(sta[tp+1]!=x)
        {
            kuai[sta[tp]]=tot;
            vis[sta[tp]]=0;
            --tp;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&d);
    scanf("%s",s+1);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    cin>>b[i].x>>b[i].hx>>b[i].y>>b[i].hy;
    for(int i=1;i<=n;++i)
    {
        if(s[i]=='x')
        book[++ji]=i;
    }
    for(int i=0;i<=(1<<d)-1;++i)
    {
        for(int j=0;j<=d-1;++j)
        {
            if((1<<j)&i)
            s[book[j+1]]='a';
            else 
            s[book[j+1]]='b';
        }
        for(int j=1;j<=cnt;++j)
        {
            a[i].to=0;
            a[i].next=0;
        }
        memset(hed,0,sizeof(hed));
        cnt=0;
        ct=0;
        for(int i=1;i<=n;++i)
        {
            if(s[i]=='a')
            {
                cur[i][0]='B';
                cur[i][1]='C';
            }
            else if(s[i]=='b')
            {
                cur[i][0]='A';
                cur[i][1]='C';
            }
            else
            {
                cur[i][0]='A';
                cur[i][1]='B';
            }
        }
        for(int j=1;j<=m;++j)
        {
            if(s[b[j].x]+1-'a'==b[j].hx+1-'A')
            continue;
            if(s[b[j].y]+1-'a'==b[j].hy+1-'A')
            {
                if(b[j].hx==cur[b[j].x][0])
                {
                    add(b[j].x,b[j].x+n);
                    u[++ct]=b[j].x;
                    v[ct]=b[j].x+n;                 
                }
                else
                {
                    add(b[j].x+n,b[j].x);
                    u[++ct]=b[j].x+n;
                    v[ct]=b[j].x;   
                }
            }           
            else
            {
                if(b[j].hx==cur[b[j].x][0]&&b[j].hy==cur[b[j].y][0])
                {
                    add(b[j].x,b[j].y);
                    u[++ct]=b[j].x;
                    v[ct]=b[j].y;
                    add(b[j].y+n,b[j].x+n);//Äæ·ñÃüÌâ¶Ô³Æ 
                    u[++ct]=b[j].y+n;
                    v[ct]=b[j].x+n;
                }
                else if(b[j].hx==cur[b[j].x][0]&&b[j].hy==cur[b[j].y][1])
                {
                    add(b[j].x,b[j].y+n);
                    u[++ct]=b[j].x;
                    v[ct]=b[j].y+n;
                    add(b[j].y,b[j].x+n);//Äæ·ñÃüÌâ¶Ô³Æ 
                    u[++ct]=b[j].y;
                    v[ct]=b[j].x+n;
                }
                else if(b[j].hx==cur[b[j].x][1]&&b[j].hy==cur[b[j].y][0])
                {
                    add(b[j].x+n,b[j].y);
                    u[++ct]=b[j].x+n;
                    v[ct]=b[j].y;
                    add(b[j].y+n,b[j].x);//Äæ·ñÃüÌâ¶Ô³Æ 
                    u[++ct]=b[j].y+n;
                    v[ct]=b[j].x;
                }
                else if(b[j].hx==cur[b[j].x][1]&&b[j].hy==cur[b[j].y][1])
                {
                    add(b[j].x+n,b[j].y+n);
                    u[++ct]=b[j].x+n;
                    v[ct]=b[j].y+n;
                    add(b[j].y,b[j].x);//Äæ·ñÃüÌâ¶Ô³Æ 
                    u[++ct]=b[j].y;
                    v[ct]=b[j].x;
                }
            }
        }
        shu=0;
        tot=0;
        memset(kuai,0,sizeof(kuai));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        tp=0;
        for(int j=1;j<=2*n;++j)
        {
            if(!dfn[j])
            tarjan(j);
        }
        pan=0;
        for(int j=1;j<=n;++j)
        {
            if(kuai[j]==kuai[j+n])
            {
                pan=1;
                break;
            }
        }
        if(pan==1)
        continue;
        pd=1;       
        for(int j=1;j<=n;++j)
        {
            if(kuai[j]<kuai[j+n])
            {
                if(s[j]=='a')
                printf("B");
                else
                printf("A");
            }
            else
            {
                if(s[j]=='c')
                printf("B");
                else 
                printf("C");
            }
        }       
        if(pd==1)
        {
            printf("\n");
            break;
        }
    }
    if(pd==0)
    printf("-1\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/81161179
今日推荐