题面
解析
一道非常有趣的2-sat题
一开始我就想偏了,我想给每一张地图建3个点分别代表A, B, C车,然后发现不会连边(就是菜到没看出来这道题怎么用2-sat),于是看了看思路,自己把代码搞出来,细细想来这个题还是很巧妙的
假如每一张地图建3个点,由于 d<=8 , 近$frac{1}{3}$的点会浪费,因此我们删去不能选的点,绝大部分地图都只有两个点了。这时先不考虑存在x的情况,于是所有地图就只有2个点,在2个点中选一个作为地图的选择,会有许多限制关系,那么很明显的2-sat了。考虑如何对题目中的四元组$(i, h_{i}, j, h_{j})$连边, 当然是分情况讨论,假设点$i$代表$h_{i}$, 点$i'$是点$i$的镜像点,点$j$与点$j'$同理, 如果$i$号点恰好不能选$h_{i}$,那就不连边;如果$i$号点可以选$h_{i}$但$j$号点不能选$h_{j}$, 那么强制让$i$号点选择除$h_{i}$以外的那个点,即$i ightarrow i'$;如果$i$号点可以选$h_{i}$并且$j$号点可以选$h_{j}$,那么$i ightarrow j$,$j' ightarrow i'$(逆否命题)。至此建图结束,剩下的就是tarjan了,分类讨论的部分可以结合下面的代码看看,我写在了work函数内
然后就是存在x的情况了,d很小,考虑暴力枚举每一张x图的车,我们已经建好了一张地图两辆车的2-sat的图,那么枚举每一张x图时要选出2辆车,由于x图是在3辆车中选一辆车,因此每一张x图有两种选法才能覆盖到跑x图的3种车,我是用的(A, C),与(B, C), 这样就没有遗漏的枚举出x图的情况了。枚举的时间是$2^{d}$ ,每一次重新建图,跑tarjan,因此总时间复杂度是$O(2^{d}(n+m))$
Special Judge的存在所以我没过样例还是AC了
代码:
#include<cstdio> #include<iostream> #include<vector> #include<algorithm> using namespace std; const int maxn = 50004; template<class T> inline void read(T &re) { T fl = 1;char c; while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')fl=-1; re=c-'0'; while((c=getchar())&&(c>='0'&&c<='9'))re=(re<<3)+(re<<1)+c-'0'; re*=fl; } int n, m, d, rel[2][maxn];//A:1, B:2, C:3 char s[maxn]; int cnt, timer, top, stak[maxn<<1], dfn[maxn<<1], low[maxn<<1], bel[maxn<<1], xpos[10]; bool vis[maxn<<1]; vector<int> G[maxn<<1]; struct requir{ int a, b; char ca, cb; }req[maxn<<1]; void tarjan(int x) { low[x] = dfn[x] = ++timer; stak[++top] = x; vis[x] = 1; for(unsigned int i = 0; i < G[x].size(); ++i) { int id = G[x][i]; if(!dfn[id]) { tarjan(id); low[x] = min(low[x], low[id]); } else if(vis[id]) low[x] = min(low[x], dfn[id]); } if(dfn[x] == low[x]) { cnt++; int t; do { t = stak[top--]; vis[t] = 0; bel[t] = cnt; } while(t != x); } } bool work() { timer = cnt = 0; for(int i = 1; i <= (n<<1); ++i) { bel[i] = dfn[i] = low[i] = 0; G[i].clear(); } for(int i = 1; i <= m; ++i) { if(s[req[i].a] == req[i].ca) continue; if(s[req[i].b] == req[i].cb) { int x = (rel[1][req[i].a] + 'a' - 1 == req[i].ca); if(x == 1) G[req[i].a+n].push_back(req[i].a); else G[req[i].a].push_back(req[i].a+n); } else { int x = (rel[1][req[i].a] + 'a' - 1 == req[i].ca); int y = (rel[1][req[i].b] + 'a' - 1 == req[i].cb); if(x == 1) { if(y == 1) { G[req[i].a+n].push_back(req[i].b+n); G[req[i].b].push_back(req[i].a); } else { G[req[i].a+n].push_back(req[i].b); G[req[i].b+n].push_back(req[i].a); } } else { if(y == 1) { G[req[i].a].push_back(req[i].b+n); G[req[i].b].push_back(req[i].a+n); } else { G[req[i].a].push_back(req[i].b); G[req[i].b+n].push_back(req[i].a+n); } } } } for(int i = 1; i <= (n<<1); ++i) if(!dfn[i]) tarjan(i); for(int i = 1; i <= n; ++i) if(bel[i] == bel[i+n]) return 0; return 1; } void dfs(int x) { if(x > d) { bool fl = work(); if(fl) { for(int i = 1; i <= n; ++i) printf("%c", rel[bel[i] > bel[i+n]][i] + 'A' - 1); exit(0); } else return; } for(int i = 1; i <= 2; ++i) { rel[0][xpos[x]] = 3 - i; rel[1][xpos[x]] = 3; s[xpos[x]] = 'a' + i - 1; dfs(x+1); } } int main() { read(n);read(d); scanf("%s", s+1); d = 0; for(int i = 1; i <= n; ++i) { if(s[i] == 'x') xpos[++d] = i; else if(s[i] == 'a') { rel[0][i] = 2; rel[1][i] = 3; } else if(s[i] == 'b') { rel[0][i] = 1; rel[1][i] = 3; } else { rel[0][i] = 1; rel[1][i] = 2; } } read(m); for(int i = 1; i <= m; ++i) { char ch[4]; read(req[i].a); scanf("%s", ch); req[i].ca = ch[0] - 'A' + 'a'; read(req[i].b); scanf("%s", ch); req[i].cb = ch[0] - 'A' + 'a'; } dfs(1); printf("-1"); return 0; }