zoukankan      html  css  js  c++  java
  • Luogu P3825 [NOI2017]游戏(2-SAT)

    P3825 [NOI2017]游戏

    题意

    题目背景

    狂野飙车是小(L)最喜欢的游戏。与其他业余玩家不同的是,小(L)在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略。

    题目描述

    (L)计划进行(n)场游戏,每场游戏使用一张地图,小(L)会选择一辆车在该地图上完成游戏。

    (L)的赛车有三辆,分别用大写字母(A,B,C)表示。地图一共有四种,分别用小写字母(x,a,b,c)表示。其中,赛车(A)不适合在地图(a)上使用,赛车(B)不适合在地图(b)上使用,赛车(C)不适合在地图(c)上使用,而地图(x)则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有(d)张。

    (n)场游戏的地图可以用一个小写字母组成的字符串描述。例如:(S=xaabxcbc)表示小(L)计划进行(8)场游戏,其中第(1)场和第(5)场的地图类型是(x),适合所有赛车,第(2)场和第(3)场的地图是a,不适合赛车(A),第(4)场和第(7)场的地图是(b),不适合赛车(B),第(6)场和第(8)场的地图是(c),不适合赛车(C)

    (L)对游戏有一些特殊的要求,这些要求可以用四元组((i,h_i,j,h_j))来描述,表示若在第(i)场使用型号为(h_i)的车子,则第(j)场游戏要使用型号为(h_j)的车子。

    你能帮小(L)选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出"-1"(不含双引号)。

    输入输出格式

    输入格式:

    输入第一行包含两个非负整数(n,d)

    输入第二行为一个字符串(S)(n,d,S)的含义见题目描述,其中(S)包含(n)个字符,且其中恰好(d)个为小写字母(x)

    输入第三行为一个正整数(m),表示有(m)条用车规则。接下来(m)行,每行包含一个四元组(i,h_i,j,h_j),其中(i,j)为整数,(h_i,h_j)为字符(a,b)(c),含义见题目描述。

    输出格式:

    输出一行。

    若无解输出"-1"(不含双引号)。

    若有解,则包含一个长度为(n)的仅包含大写字母(A,B,C)的字符串,表示小(L)在这(n)场游戏中如何安排赛车的使用。如果存在多组解,输出其中任意一组即可。

    因为(spacial judge),最后一行不要输出回车。

    输入输出样例

    输入样例#1:

    3 1
    xcc
    1
    1 A 2 B
    

    输出样例#1:

    ABA
    

    说明

    【样例1解释】

    (L)计划进行(3)场游戏,其中第(1)场的地图类型是(x),适合所有赛车,第(2)场和第(3)场的地图是(c),不适合赛车(C)

    (L)希望:若第(1)场游戏使用赛车(A),则第(2)场游戏使用赛车(B)。那么为这(3)场游戏分别安排赛车(A,B,A)可以满足所有条件。若依次为(3)场游戏安排赛车为(BBB)(BAA)时,也可以满足所有条件,也被视为正确答案。但依次安排赛车为(AAB)(ABC)时,因为不能满足所有条件,所以不被视为正确答案。

    P3825

    思路

    这道水题怎么还是黑的? --huyufeifei

    调了一晚上这道题,真的毒瘤。

    我们先不考虑(x)地图,那么剩余的地图每种只有两辆赛车可跑。再根据题目给的约束条件,我们就可以用(2-SAT)来解决这个问题。

    那么带上(x)地图怎么办呢?既然(d)很小,那我们就暴力枚举!把(x)地图强行换成(a,b,c)中的一张,再来判断是否可行。最终复杂度为(O(3^dm)),显然很爆炸。考虑到如果我们只枚举(a,b),其实就可以覆盖(x)地图可以使用(A,B,C)三种赛车的条件,那就不枚举(c)好了。最终时间复杂度(O(2^dm))

    我在做这题时出现了很多问题,调试了很久,枚举如下:

    • 因为每张地图对应的赛车不同,所以不同地图在(2-SAT)中的两个取值完全不同,要注意区分。
    • 建边时要建两条边。对于如果(a)那么(b)这个条件,不能只建边((a,b)),还要建边((b+n,a+n))(想一想为什么)。
    • 暴力枚举不要打挂(没错,我因为打挂了暴力调了好久)。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MAXN=2e5+5,MAXM=4e5+5;
    LL n,d,m,tot,js,dfn[MAXN],low[MAXN],bel[MAXN];
    LL x[MAXM],y[MAXM];
    LL cnt,top[MAXN],to[MAXM],nex[MAXM];
    string str;
    char xx[MAXM],yy[MAXM];
    bool vis[MAXN];
    stack<LL>S;
    LL read()
    {
        bool f=true;LL re=0;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=false;ch=getchar();}
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return f?re:-re;
    }
    void add_edge(LL x,LL y){to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;}
    char fst(char y)
    {
        if(y=='A') return 'B';
        else if(y=='B') return 'C';
        else if(y=='C') return 'A';
    }
    char scd(char y)
    {
        if(y=='A') return 'C';
        else if(y=='B') return 'A';
        else if(y=='C') return 'B';
    }
    void tarjan(LL now)
    {
        dfn[now]=low[now]=++tot,vis[now]=true,S.push(now);
        for(LL i=top[now];i;i=nex[i])
            if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
            else if(vis[to[i]]) low[now]=min(low[now],dfn[to[i]]);
        if(dfn[now]==low[now])
        {
            bel[now]=++js,vis[now]=false;
            while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,S.pop();
            S.pop();
        }
    }
    bool check()
    {
        cnt=tot=js=0;
        memset(dfn,0,sizeof dfn);
        memset(top,0,sizeof top);
        for(LL i=1;i<=m;i++)
        {
            char f1=fst(str[x[i]]),s1=scd(str[x[i]]),f2=fst(str[y[i]]),s2=scd(str[y[i]]);
            if(xx[i]==str[x[i]]) continue;
            else if(yy[i]==str[y[i]])
            {
                if(xx[i]==f1) add_edge(x[i],x[i]+n);
                else if(xx[i]==s1) add_edge(x[i]+n,x[i]);
            }
            else if(xx[i]==f1&&yy[i]==f2) add_edge(x[i],y[i]),add_edge(y[i]+n,x[i]+n);
            else if(xx[i]==f1&&yy[i]==s2) add_edge(x[i],y[i]+n),add_edge(y[i],x[i]+n);
            else if(xx[i]==s1&&yy[i]==f2) add_edge(x[i]+n,y[i]),add_edge(y[i]+n,x[i]);
            else if(xx[i]==s1&&yy[i]==s2) add_edge(x[i]+n,y[i]+n),add_edge(y[i],x[i]);
        }
        for(LL i=1;i<=(n<<1);i++) if(!dfn[i]) tarjan(i);
        for(LL i=1;i<=n;i++) if(bel[i]==bel[i+n]) return false;
        for(LL i=1;i<=n;i++)
            if(bel[i]<bel[i+n]) putchar(fst(str[i]));
            else putchar(scd(str[i]));
        return true;
    }
    bool dfs(LL now,LL hjj)
    {
        if(hjj==d)
        {
            if(check()) return true;
            return false;
        }
        while(str[now]!='X') now++;
        str[now]='A';
        if(dfs(now+1,hjj+1)) return true;
        str[now]='B';
        if(dfs(now+1,hjj+1)) return true;
        str[now]='X';
        return false;
    }
    int main()
    {
        cin>>n>>d;
        cin>>str;str=" "+str;
        for(LL i=1;i<=n;i++) str[i]=toupper(str[i]);
        cin>>m;
        for(LL i=1;i<=m;i++) cin>>x[i]>>xx[i]>>y[i]>>yy[i];
        if(!dfs(1,0)) printf("-1");
        return 0;
    }
    
  • 相关阅读:
    【Cocos2d-x for WP8 学习整理】(1)创建一个新项目
    与本机其他应用交互的简单介绍
    Windows Phone GB2312
    Windows Phone 横竖屏切换动画
    Linq To VisualTree
    Epub基础知识介绍
    【使用Unity开发Windows Phone上的2D游戏】(2)初识工具
    操作系统Unix、Windows、Mac OS、Linux的故事
    PHP开发环境搭建
    linux和mac
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9898053.html
Copyright © 2011-2022 走看看