[uoj317][NOI2017]游戏——2-SAT

题目大意:

小 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, hi, j, hj) 来描述,表示若
在第 i 场使用型号为 hi 的车子,则第 j 场游戏要使用型号为 hj 的车子。
你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如
果无解,输出 “-1’’(不含双引号)。

思路:

发现x这种型号的赛道很不和谐,然后发现数据范围很小,所以可以考虑 3d 3 d 枚举每一个x赛道的型号。
但是 3dn 3 d n 显然过不去,其实没有必要枚举3种情况,如果最后答案为 A A ,那么只有枚举到a是会不合法,再任意枚举任意一种都会有解,所以枚举两个就已经够了。
考虑不同的限制该如何连边,对于不存在起点的限制可以直接忽略,对于不存在终点的限制就表示起点是不可以选择的,所以直接这个起点连向同一个集合的另外一个点即可。
然后就转化为了2-SAT模型了,直接连边强连通分量缩点再判断即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("uoj317.in","r",stdin);
    freopen("uoj317.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=5e4+10;
const int maxm=1e5+10;
const int maxd=8+10;
int n,d,m,ty[maxn],pos[maxd],cnt_d;
char s[maxn];
struct node{int x,t1,y,t2;}lim[maxm];
vector<int>G[maxn*3];
int ty1[maxn],ty2[maxn];

void init(){
    read(n); read(d);
    scanf("%s",s+1);
    REP(i,1,n){
        ty[i]=min(s[i]-'a',3);
        if(ty[i]==3)pos[++cnt_d]=i;
        else{
            if(ty[i]==0)ty1[i]=1,ty2[i]=2;
            else if(ty[i]==1)ty1[i]=0,ty2[i]=2;
            else ty1[i]=0,ty2[i]=1;
        }
    }
    read(m);
    REP(i,1,m){
        read(lim[i].x);
        scanf("%s",s);
        lim[i].t1=s[0]-'A';
        read(lim[i].y);
        scanf("%s",s);
        lim[i].t2=s[0]-'A';
    }
}

int low[maxn*3],dfn[maxn*3],cnt_dfn,bel[maxn*3],cnt_scc;
stack<int>stk;

void tarjan(int u){
    low[u]=dfn[u]=++cnt_dfn;
    stk.push(u);
    for(int sz=G[u].size()-1,i=0;i<=sz;++i){
        int v=G[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!bel[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        ++cnt_scc;
        for(int p=0;p!=u;stk.pop()){
            p=stk.top();
            bel[p]=cnt_scc;
        }
    }
}

bool work(){
    cnt_dfn=cnt_scc=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(bel,0,sizeof(bel));
    REP(i,1,n*3)G[i].clear();
    REP(i,1,m){
        int x=lim[i].x,t1=lim[i].t1,y=lim[i].y,t2=lim[i].t2;
        if(t1==ty[x])continue;
        else if(t2==ty[y]){
            G[x+t1*n].push_back(x+(3-ty[x]-t1)*n);
        }
        else{
            G[x+t1*n].push_back(y+t2*n);
            G[y+(3-ty[y]-t2)*n].push_back(x+(3-ty[x]-t1)*n);
        }
    }
    REP(i,1,n){
        if(!dfn[i+ty1[i]*n])tarjan(i+ty1[i]*n);
        if(!dfn[i+ty2[i]*n])tarjan(i+ty2[i]*n);
    }
    REP(i,1,n)if(bel[i+ty1[i]*n]==bel[i+ty2[i]*n])return false;
    return true;
}

bool dfs(int k){
    if(k>d)return work();
    REP(i,0,1){
        if((double)clock()/CLOCKS_PER_SEC>0.9)return false;
        ty[pos[k]]=i;
        if(ty[pos[k]]==0)ty1[pos[k]]=1,ty2[pos[k]]=2;
        else ty1[pos[k]]=0,ty2[pos[k]]=2;
        if(dfs(k+1))return true;
    }
    return false;
}

int main(){
    File();
    init();
    if(!dfs(1)){
        puts("-1");
        return 0;
    }
    REP(i,1,n)if(bel[i+ty1[i]*n]<bel[i+ty2[i]*n])
        printf("%c",ty1[i]+'A');
    else printf("%c",ty2[i]+'A');
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值