zoukankan      html  css  js  c++  java
  • BZOJ 4945 NOI2017 游戏 搜索+2-SAT

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4945

    分析:

      首先考虑没有x的情况,发现有一个明显的推理模型,容易看出来可以用2-SAT做。

      然后考虑有x的情况,发现最多只有8个x,不难想到可以搜索每个x为a,b,c中的哪个然后跑2-SAT。但是算算时间发现会T。

      再仔细分析,发现只需要枚举两种情况就可以了。因为可行的对象已经全部在这两种情况里面包含了!

      发现真的tarjan比另外一个算法快......事实证明另外一个算法(我叫不出名字ORZ)是可以被卡成O(NM)的。(从此入了tarjan的教。。。)

      此题细节令人开心。

      时间复杂度O((N+M)*2^x)。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 const int maxn=50005;
     14 const int maxm=100005;
     15 
     16 int N,D,M;
     17 char S[maxn];
     18 struct edge{ int to,next; }E[maxm<<1];
     19 struct data{ int i,j; char hi,hj; }da[maxm];
     20 int first[maxn<<1],_first[maxn<<1],np,pos[10],cnt,stk[maxn<<1],top;
     21 int dfn[maxn<<1],sccno[maxn<<1],dfs_clock,scc_cnt,low[maxn<<1];
     22 bool bad[maxn<<1],_bad[maxn<<1];
     23 
     24 void _scanf(int &x)
     25 {
     26     x=0;
     27     char ch=getchar();
     28     while(ch<'0'||ch>'9') ch=getchar();
     29     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
     30 }
     31 void _scanf(char &x)
     32 {
     33     x=getchar();
     34     while(!isalpha(x)) x=getchar();
     35 }
     36 void add_edge(int u,int v,int *f)
     37 {
     38     E[++np]=(edge){v,f[u]};
     39     f[u]=np;
     40 }
     41 int id(int i,char a)
     42 {
     43     if(S[i]=='a') return i*2-(a=='B'?1:0);
     44     return i*2-(a=='A'?1:0);
     45 }
     46 int _id(int i,bool k)
     47 {
     48     if(k) return S[i]=='a'?1:0;
     49     return S[i]=='c'?1:2;
     50 }
     51 void data_in()
     52 {
     53     _scanf(N);_scanf(D);scanf("%s",S+1);_scanf(M);
     54     int a,b; char hi,hj;
     55     for(int i=1;i<=N;i++)
     56         if(S[i]=='x') pos[++cnt]=i;
     57     cnt=0;
     58     for(int i=1;i<=M;i++){
     59         _scanf(a);_scanf(hi);_scanf(b);_scanf(hj);
     60         if(S[a]-hi==32) continue;
     61         if(S[a]=='x'||S[b]=='x'){
     62             da[++cnt]=(data){a,b,hi,hj}; 
     63             continue;
     64         }
     65         if(S[b]-hj==32){ bad[id(a,hi)]=1; continue; }
     66         a=id(a,hi),b=id(b,hj);
     67         add_edge(a,b,first); add_edge((b-1^1)+1,(a-1^1)+1,first);
     68     }
     69 }
     70 void tarjan_scc(int i)
     71 {
     72     if(_bad[i]) return;
     73     dfn[i]=low[i]=++dfs_clock;
     74     stk[++top]=i;
     75     for(int p=_first[i];p;p=E[p].next){
     76         int j=E[p].to;
     77         if(dfn[j]){
     78             if(!sccno[j]) low[i]=min(low[i],dfn[j]);
     79             continue;
     80         }
     81         tarjan_scc(j);
     82         low[i]=min(low[i],low[j]);
     83     }
     84     if(low[i]==dfn[i]){
     85         scc_cnt++;
     86         while(stk[top]!=i) sccno[stk[top--]]=scc_cnt;
     87         sccno[stk[top--]]=scc_cnt;
     88     }
     89 }
     90 bool judge()
     91 {
     92     memset(dfn,0,sizeof(dfn));
     93     memset(sccno,0,sizeof(sccno));
     94     memset(low,0,sizeof(low));
     95     dfs_clock=scc_cnt=top=0;
     96     for(int i=1;i<=N*2;i++)
     97         if(!dfn[i]) tarjan_scc(i);
     98     for(int i=1;i<=N;i++)
     99         if(sccno[i*2-1]==sccno[i*2]) return 0;
    100     return 1;
    101 }
    102 bool run(int i)
    103 {
    104     if(i>D){
    105         memcpy(_first,first,sizeof(first));
    106         memcpy(_bad,bad,sizeof(bad));
    107         int tmp=np,a,b;
    108         for(int k=1;k<=cnt;k++){
    109             if(S[da[k].i]-da[k].hi==32) continue;
    110             if(S[da[k].j]-da[k].hj==32){ _bad[id(da[k].i,da[k].hi)]=1; continue; }
    111             a=id(da[k].i,da[k].hi),b=id(da[k].j,da[k].hj);
    112             add_edge(a,b,_first); add_edge((b-1^1)+1,(a-1^1)+1,_first);
    113         }
    114         np=tmp;
    115         return judge();
    116     }
    117     S[pos[i]]='a'; if(run(i+1)) return 1;
    118     S[pos[i]]='b'; if(run(i+1)) return 1;
    119     return 0;
    120 }
    121 void work()
    122 {
    123     if(!run(1)) printf("%d
    ",-1);
    124     else{
    125         for(int i=1;i<=N;i++){
    126             if(!sccno[i*2-1]) putchar('A'+_id(i,0));
    127             else if(!sccno[i*2]) putchar('A'+_id(i,1));
    128             else if(sccno[i*2]<sccno[i*2-1]) putchar('A'+_id(i,0));
    129             else putchar('A'+_id(i,1));
    130         }
    131         putchar('
    ');
    132     }
    133 }
    134 int main()
    135 {
    136     data_in();
    137     work();
    138     return 0;
    139 }
    View Code
  • 相关阅读:
    为什么硬链接不能链接目录、文件inode 和目录 dentry 的区别联系
    LVM 详解
    pwd 命令详解
    type 命令详解
    查看文件中字符出现次数
    lesson
    xml linq
    新系统配置
    空合并运算符(??):
    dos.ORM配置和使用
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8735163.html
Copyright © 2011-2022 走看看