bzoj3825 NOI2017 游戏

题目背景

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

题目描述

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

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

nn 场游戏的地图可以用一个小写字母组成的字符串描述。例如:S=xaabxcbc表示小 L 计划进行88 场游戏,其中第11 场和第55 场的地图类型是x,适合所有赛车,第22 场和第33 场的地图是a,不适合赛车A,第44 场和第77 场的地图是b,不适合赛车B,第66 场和第88 场的地图是c,不适合赛车C

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

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

输入输出格式

输入格式:

 

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

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

输入第三行为一个正整数mm ,表示有mm 条用车规则。接下来mm 行,每行包含一个四元组i, h_i, j, h_ji,hi,j,hj ,其中i, ji,j 为整数,h_i, h_jhi,hj 为字符abc,含义见题目描述。

 

输出格式:

 

输出一行。

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

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

题意:

     有n个场地,三个赛车,每个场地适合某两种三种赛车,再给出m个限制条件,形式为A x B y 即A使用x,B必须使用y;

题解:

    ①2-SAT

    如果每张图只能选两个车,具体的对于每一个条件,连如图的有向边:意思就是如果A号场地用了x车,B号场地一定用了y车,反之,如果B号场地不用y车,那么A号场地一定不是x车。可以发现这个图的对称性。

    对这个图跑缩点,在一个强联通里的所有点表示逻辑上可以互相推理,同一个场地A的x和y不能同时被选。枚举A,如果A的两个选择在一个联通里,则无法构造出方案,否则可以;

    ②输出方案:随便从一个A开始,任意选择一个联通,选择联通里的所有A,并将联通里所有的选择的另一种选择所在联通和这些联通的前驱联通都删掉,最后可以构造出解;这样子本来是要反向拓扑排序,但是由于tarjan算法做完之后已经是反拓扑序,所以就不需要再写一遍;

     ③因为题中三种车都可以跑的图的个数d很小,那么对于每一个这样的图枚举两种情况就可以表达三种车了;

    

#include<bits/stdc++.h>
using namespace std;
const int N = 2000010,da = 'a' - 1,dA = 'A' - 1;
int n,m,d,s[N],idx[N][10],typ[N],dfn[N],low[N],bl[N],tot,st[N],top,cnt,hd[N],o,preo,prehd[N],del[N],ans[N];
struct data{int x1,c1,x2,c2;};
vector<int>X,son[N],fm[N]; vector<data>Q;
struct Edge{int v,nt;}E[N];
char gc(){
    static char *p1,*p2,s[1000000];
    if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
    return(p1==p2)?EOF:*p1++;
}
int rd(){
    int x = 0; char c = gc();
    while(c<'0'||c>'9') c = gc();
    while(c>='0'&&c<='9') x = x *10 + c - '0',c = gc();
    return x;
}
char gt(){
    char c = gc();
    while(!isalpha(c)) c = gc();
    return c;
}
void adde(int u,int v){E[o] = (Edge){v,hd[u]}; hd[u] = o++;}
void init(int x1,int c1,int x2,int c2){
    if(!s[x1]||!s[x2]){
        Q.push_back((data){x1,c1,x2,c2});
        return ;
    }
    if(s[x1]==c1) return ;
    if(s[x2]==c2) {adde(idx[x1][c1],idx[x1][6 - s[x1] - c1]);return ;}
    adde(idx[x1][c1],idx[x2][c2]);
    adde(idx[x2][6 - s[x2] - c2],idx[x1][6 - s[x1] - c1]);
} 
void tarjan(int u){
    dfn[u] = low[u] = ++tot; st[++top] = u;
    for(int i = hd[u],v;i!=-1;i=E[i].nt){
        if(!dfn[v=E[i].v]) tarjan(v),low[u]=min(low[u],low[v]);
        else if(!bl[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        cnt++;
        do bl[st[top]]=cnt;
        while(st[top--]!=u);
    }
}
bool sat(){
    top = tot = cnt = 0;
    for(int i = 2;i <= 2*n+1;i++) dfn[i] = low[i] = bl[i] = del[i] = 0;
    for(int i = 2;i <= 2*n+1;i++) if(!dfn[i]) tarjan(i);
    for(int i = 2;i <= 2*n+1;i+=2) if(bl[i]==bl[i^1]) return false;
    return true;
}
void clear(int i){
    if(del[i])return; del[i] = 1;
    for(int j = 0;j < fm[i].size();j++) clear(fm[i][j]);
}
void update(int i){
    clear(bl[i^1]);
    ans[i/2] = typ[i]; 
}
void Print(){
    for(int i = 2;i <= 2*n+1;i++) son[bl[i]].push_back(i);
    for(int i = 2;i <= 2*n+1;i++) 
    for(int j = hd[i];j!=-1;j=E[j].nt){
        fm[bl[E[j].v]].push_back(bl[i]);
    } 
    for(int i = 1;i <= cnt;i++)if(!del[i])
        for(int j = 0;j < son[i].size();j++) 
            update(son[i][j]);
    for(int i = 1;i <= n;i++) putchar(ans[i]+dA); printf("\n");
}
int main()
{    freopen("mzoj1114.in","r",stdin);
    freopen("mzoj1114.out","w",stdout);
    n = rd(); 
    d = rd();
    for(int i = 1;i <= n;i++) {
        char c = gt(); 
        if(c!='x') {
            s[i] = c - da;
            for(int j = 1,k = 2*i;j <= 3;j++) if(s[i]!=j) idx[i][j] = k,typ[k++] = j;
        }else X.push_back(i);
    }
    m = rd();
    memset(hd,-1,sizeof(hd));
    for(int i = 1;i <= m;i++) {
        int x1,x2; char c1,c2;
        x1 = rd(); c1 = gt()-dA;
        x2 = rd(); c2 = gt()-dA;
        init(x1,c1,x2,c2);
    }
    preo = o; for(int i = 2;i <= 2*n+1;i++) prehd[i] = hd[i];
    for(int i = 0;i < (1<<d);i++){
        for(int j = 0;j < d;j++){
            int x = X[j];
            if(i&(1<<j)) s[x] = 1,typ[idx[x][2] = 2*x] = 2,typ[idx[x][3] = 2*x+1] = 3;
            else s[x] = 2,typ[idx[x][1] = 2*x] = 1,typ[idx[x][3] = 2*x+1] = 3;
        }
        o = preo; for(int i1 = 2;i1 <= 2*n+1;i1++) hd[i1] = prehd[i1];
        for(int j = 0;j < Q.size();j++) init(Q[j].x1,Q[j].c1,Q[j].x2,Q[j].c2);
        if(sat()) Print(),exit(0);
    //    for(int j = 0;j < n;j++) s[X[i]] = 0; 
    }
    puts("-1");
    return 0;
}//by tkys_Austin;

 

 


     

posted @ 2018-03-25 16:46  大米饼  阅读(271)  评论(0编辑  收藏  举报