zoukankan      html  css  js  c++  java
  • 编码

    题目描述

    Bob最近学习了一下二进制前缀编码的那一套理论。二进制编码是指一个由n个互不相同的二进制串s1,s2,...,sn构成的集合。而如果一套编码满足,对于任意的i≠j,si不是sj的前缀,那么我们称它为前缀编码。
    Bob发现了一张上面写有n行二进制编码的纸。但这张纸年代久远,有些字迹已经模糊不清。幸运的是,每一行至多只会有一个模糊的字符。
    Bob想知道这n行二进制编码是否有可能是一个前缀编码?

    输入

    输入第一行有一个整数n,表示编码的大小。
    接下来n行,每行一个由0,1及?组成的字符串。保证每一行至多有一个?

    输出

    如果这n个二进制编码可能是前缀编码那么你需要输出“YES”,否则输出“NO”。

    样例输入

    4
    00?
    0?00
    ?1
    1?0

    样例输出

    YES

    分析

    对于第i个字符串和第j个字符串,我们记(i_0)为把第i个字符串的问号变成0之后的字符串,(i_1)为把第i个字符串的问号变成0之后的字符串。
    如果(i_0)(j_x)的前缀,那么如果选择了(i_0)就必须选择(j_{xoplus1}),如果选择了(j_x),就必须选择(i_1),这样就转化成了一个2-SAT问题。
    我觉得难处理的是没有问号的字符串,问dy了好久...处理办法是,把这个点拆分为选择和不选,然后在2-SAT图里加上(不选 ightarrow选)这种边,非常机智了。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=500050;
    int ch[maxn*2][2],tot,num;
    int cur[maxn*2],bac[maxn*2];
    vector<int> G[maxn*8];
    void insert(char *s,int id) {
        int u=0;
        for(int i = 0; s[i]; ++i) {
            int c=s[i]-'0';
            if(s[i]=='?') c=(id&1);
            if(!ch[u][c]) ch[u][c]=++tot;
            u=ch[u][c];
        }
        if(!cur[u]) {
            cur[u]=++num,bac[u]=++num;
            G[id].push_back(cur[u]);
            G[bac[u]].push_back(id^1);
        }
        else {
            G[id].push_back(bac[u]);
            G[cur[u]].push_back(id^1);
            ++num;
            G[id].push_back(num),G[cur[u]].push_back(num),cur[u]=num;
            ++num;
            G[num].push_back(id^1),G[num].push_back(bac[u]),bac[u]=num;
        }
    }
    void dfs(int u,int pre1,int pre2) {
        if(cur[u]) {
            if(!pre1) pre1=cur[u],pre2=bac[u];
            else {
                G[cur[u]].push_back(pre2);
                G[pre1].push_back(bac[u]);
                ++num;
                G[pre1].push_back(num),G[cur[u]].push_back(num),pre1=num;
                ++num;
                G[num].push_back(pre2),G[num].push_back(bac[u]),pre2=num;
            }
        }
        if(ch[u][0]) dfs(ch[u][0],pre1,pre2);
        if(ch[u][1]) dfs(ch[u][1],pre1,pre2);
    }
    int n,pre[maxn*8],lowlink[maxn*8],dfs_no,sccCnt,sccno[maxn*8];
    stack<int> stk;
    void dfs(int u) {
        pre[u]=lowlink[u]=++dfs_no;
        stk.push(u);
        for(auto v:G[u]) {
            if(!pre[v]) dfs(v),lowlink[u]=min(lowlink[u],lowlink[v]);
            else if(!sccno[v]) lowlink[u]=min(lowlink[u],pre[v]);
        }
        if(pre[u]==lowlink[u]) {
            ++sccCnt;
            while(1) {
                int x=stk.top();stk.pop();
                sccno[x]=sccCnt;
                if(x==u) break;
            }
        }
    }
    char str[maxn];
    int main(int argc, char const *argv[])
    {
        scanf("%d", &n);
        num=n*2+2;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%s", str);
            insert(str,i+i);
            int len=strlen(str);
            if(count(str,str+len,'?')) insert(str,i*2+1);
            else G[i*2+1].push_back(i+i);
        }
        dfs(0,0,0);
        for(int i = 1; i <= n; ++i) {
            if(!pre[i*2]) dfs(i*2);
            if(!pre[i*2+1]) dfs(i*2+1);
            if(sccno[i*2]==sccno[i*2+1]) {
                puts("NO");
                return 0;
            }
        }
        puts("YES");
        return 0;
    }
    
  • 相关阅读:
    Windows Server 2003 NLB负载均衡(集群)配置详解
    SQL Server 数据库中关于死锁的分析
    SQL Server 性能调优(一)——从等待状态判断系统资源瓶颈
    RSync实现文件备份同步
    C# 中的委托和事件
    图解用WAS对Web服务器进行压力测试(was下载)
    Windows 之间用rsync同步数据(cwRsyncServer配置)
    SQLServer2005在复制功能中创建发布订阅
    【总结】C# 线程同步技术(一)之 Join 方法
    也来说说C#异步委托
  • 原文地址:https://www.cnblogs.com/sciorz/p/9491516.html
Copyright © 2011-2022 走看看