• [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
  • 相关阅读:
    flex space-between最后一行对齐问题的解决方案
    如何在父级下访问v-slot的值——vuejs
    flex下省略号的问题解决
    Typescript使用字符串联合类型代替枚举类型
    flex三个对齐属性的记忆方式
    JS中的slice()和splice()的区别以及记忆方式
    JS中的call,apply和bind及记忆方式
    Vue 还是 React 还是 Angular ?
    利用ES6的Promise.all实现至少请求多长时间
    .net core <environment> 不起作用
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9733063.html
Copyright © 2020-2023  润新知