bzoj3825 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,hi,j,hj) 来描述,表示若在第i 场使用型号为hi 的车子,则第j场游戏要使用型号为hj 的车子。
你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出 “-1
’’(不含双引号)。
输入输出格式
输入格式:
输入第一行包含两个非负整数n,d 。
输入第二行为一个字符串S 。n,d,S 的含义见题目描述,其中S 包含n 个字符,且其中恰好d 个为小写字母x 。
输入第三行为一个正整数m ,表示有m 条用车规则。接下来m 行,每行包含一个四元组i,hi,j,hj ,其中i,j 为整数,hi,hj 为字符a、b或c,含义见题目描述。
输出格式:
输出一行。
若无解输出 “-1
’’(不含双引号)。
若有解,则包含一个长度为n 的仅包含大写字母A、B、C的字符串,表示小 L 在这n 场游戏中如何安排赛车的使用。如果存在多组解,输出其中任意一组即可。
题意:
有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;