[NOI2017]游戏 2-sat

~~~题面~~~

题解:

  首先观察到,如果没有x的话,这就是一个2-sat问题。

  建图方式:对于限制d1 c1 d2 c2,其中d1, d2分别代表比赛编号,c1, c2代表出场的赛车。

  1,如果d1不能选c1,那么该限制是不会起到作用的,所以不连边。

  2,否则如果d2不能选c2,那么意味这d1-c1不能被选,所以连d1-c1 --- > d1-c2的边,表示必须取d1-c2。

  3,否则都可以选,所以连d1-c1 ---> d2-c2 , d1-c2 ---> d2-c1.

  跑tarjan求强连通分量即可。

  

  那么有x应该怎么做?

  观察到对于一组数据,x最多有8场,所以3^8枚举每场x的比赛是abc中的哪种(不选哪辆车),然后在跑2-sat即可。

  这里输出方案可以不用反向建边+拓扑排序,因为栈是后进先出,所以先出栈的点刚好是反向建边+拓扑排序后先遇到的点,因此只需要记录每个点所在的联通块编号,然后对于每场比赛选择联通块编号小的方案输出即可。

  题目数据极水,A了也不一定是正确代码,请特别注意检查代码正确性。(如果你发现我有哪里错了也可以告诉我QAQ)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 300100
  5 #define ac 1000000
  6 
  7 int n, d, timer, all, m;
  8 int s[AC], dfn[AC], low[ac], belong[ac], d1[AC], c1[AC], d2[AC], c2[AC];
  9 int sta[AC], top;
 10 int Head[AC], Next[ac], date[ac], tot;
 11 char ss[AC];
 12 bool flag, z[AC];
 13 
 14 inline int read()
 15 {
 16     int x = 0;char c = getchar();
 17     while(c > '9' || c < '0') c = getchar();
 18     while(c >= '0' && c <= '9') x = 10 * x + c - '0', c = getchar();
 19     return x;
 20 }
 21 
 22 inline void upmin(int &a, int b)
 23 {
 24     if(b < a) a = b;
 25 }
 26 
 27 inline void add(int f, int w)
 28 {
 29     date[++tot] = w, Next[tot] = Head[f], Head[f] = tot;
 30     //printf("%d ---> %d
", f, w);
 31 }
 32 
 33 void tarjan(int x)
 34 {
 35     int now;
 36     dfn[x] = low[x] = ++ timer, sta[++top] = x, z[x] = true;
 37     for(R i = Head[x]; i; i = Next[i])
 38     {
 39         now = date[i];
 40         if(!dfn[now])
 41         {
 42             tarjan(now);
 43             upmin(low[x], low[now]);
 44         }
 45         else if(z[now]) upmin(low[x], low[now]);//已经出栈的无需考虑
 46     }
 47     if(low[x] == dfn[x])
 48     {
 49         ++all;
 50         while(1)
 51         {
 52             now = sta[top--], belong[now] = all, z[now] = false;//标记出栈
 53             if(now == x) break;
 54         }
 55     }
 56 }
 57 
 58 void init()
 59 {
 60     tot = all = timer = 0;
 61     memset(Head, 0, sizeof(Head));
 62     memset(dfn, 0, sizeof(dfn));
 63     memset(z, 0, sizeof(z));
 64 }
 65 
 66 inline int get(int x, int color)
 67 {
 68     if(s[x] == color) return 0;//不合法
 69     if(s[x] == 1) return x * 2 + color - 2;
 70     else if(s[x] == 2) return x * 2 + ((color == 1) ? 0 : 1);
 71     else return x * 2 + color - 1;
 72 }
 73 
 74 void build()
 75 {
 76     init();
 77     for(R i = 1; i <= m; i ++)
 78     {
 79         int x = get(d1[i], c1[i]), y = get(d2[i], c2[i]);
 80         if(x)
 81         {
 82             if(y) add(x, y), add(y ^ 1, x ^ 1);
 83             else add(x, x ^ 1);
 84         }
 85     }
 86     int b = n * 2 + 1;
 87     for(R i = 2; i <= b; i ++) 
 88         if(!dfn[i]) tarjan(i);
 89     for(R i = 2; i <= b; i += 2)//error !!!到b
 90         if(belong[i] == belong[i ^ 1]) return ;
 91     for(R i = 1; i <= n; i ++)
 92     {
 93         int x = i * 2;
 94         if(s[i] == 1) putchar(belong[x] < belong[x ^ 1] ? 'B' : 'C');
 95         else if(s[i] == 2) putchar(belong[x] < belong[x ^ 1] ? 'A' : 'C');
 96         else putchar(belong[x] < belong[x ^ 1] ? 'A' : 'B');
 97     }
 98     flag = true;
 99 }
100 
101 void pre()
102 {
103     char ch;
104     n = read(), d = read();
105     scanf("%s", ss + 1);
106     for(R i = 1; i <= n; i ++) 
107         if(ss[i] != 'x') s[i] = ss[i] - 'a' + 1;
108     m = read();
109     for(R i = 1; i <= m; i ++)
110     {
111         d1[i] = read(), cin >> ch, c1[i] = ch - 'A' + 1;
112         d2[i] = read(), cin >> ch, c2[i] = ch - 'A' + 1;
113     }
114 }
115 
116 void dfs(int x)
117 {
118     if(flag) return ;
119     if(x > n) 
120     {
121         build();
122         return ;
123     }
124     if(!s[x]) 
125     {
126         s[x] = 1, dfs(x + 1);
127         s[x] = 2, dfs(x + 1);
128         s[x] = 3, dfs(x + 1);
129         s[x] = 0;
130     }
131     else dfs(x + 1);
132 }
133 
134 int main()
135 {
136     freopen("in.in","r",stdin);
137     pre();
138     dfs(1);
139     if(!flag) printf("-1");
140     fclose(stdin);
141     return 0;
142 }
View Code
原文地址:https://www.cnblogs.com/ww3113306/p/9733063.html