USACO 6.3.2 Cryptcowgraphy 剪枝

本文介绍了一道USACO竞赛题目的解题思路及C++实现,通过字符串处理和搜索剪枝的方法来解决字符串解码问题。文章详细介绍了如何利用ELFhash减少重复搜索,并分享了一些提高效率的小技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://train.usaco.org/usacoprob2?a=Bc6YOT0fW9R&S=cryptcow

题目大意:字符串解码,字符串中分布有(C,O,W),每一步交换C-O, O-W中的子串,看能否最后达到目标字符串,如可以输出步数(目标字符串给出,且不含C,O,W)




字符串处理+搜索剪枝

①最直观的剪枝就是当前字符串中不含COW的前后缀必须要和目标串匹配,但仅仅如此肯定是过不了的

②上一条思想的升级版就是每个不含COW的小子串必须包含在目标串中

③在搜索的过程中很可能会出现相同解,所以要将字符串哈希查重

※此处的哈希我没有使用以前的map方法,而是学到了新技巧叫做ELFhash(),所采用的大质数是从别人的博客里看来的

搜索技巧:这道题还有一个特别的小tips就是搜索COW的时候要先搜索O,再从头尾两端分别向中心搜索CW,讲不清楚为什么,但是感觉上肯定在第一个字符(或C或O)确定的种种情况下,先搜O的后续搜索使用的时间要更平均(第一字符在头或尾的情况下),那么在总体复杂度差不多的情况下,平均即高效


我的额外处理:我在每次递归的时候传递了当前不含COW的前后缀结束的位置,这样一来在进行前两次剪枝和COW搜索的时候需要操作的范围就能更小,可以更快一点,而且反正这种向中心逼近的工作在第一条剪枝方法中也是肯定要做一次的


/*
ID: frontie1
TASK: cryptcow
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <string.h>

using namespace std;

string model_str = "Begin the Escape execution at the Break of Dawn";
char model[80] = "Begin the Escape execution at the Break of Dawn";
int modellen;
char ori[80];
bool hash_table[140000];
bool found = false;

int ELFhash(char *key){

    unsigned long h=0;
    unsigned long x=0;

    while(*key)
    {
        h=(h<<4)+(*key++);
        if( (x=h & 0xF0000000L)!=0){
          h^=(x>>24);
          h&=~x;
        }
    }
    return h % 131071;
}

void DFS(char str[], int dep, int lo, int hi)
{
    if(found) return;

    if(strcmp(str, model) == 0){
        found = true;
        printf("%d %d\n", 1, dep);
        return;
    }

    int num = ELFhash(str);
    if(hash_table[num]) return;
    else hash_table[num] = true;

    int length = strlen(str);
    int st = lo, ed = hi;
    for(;st < modellen && str[st] != 'C'; ++st){
        if(str[st] != model[st]) return;
    }
    for(int i = modellen-length+ed; i >= 0 && str[ed] != 'W'; --i, --ed){
        if(str[ed] != model[i]) return;
    }

    char segment[80];
    segment[0] = '\0';
    for(int i = st+1; i <= ed; ++i){
        if(str[i] == 'C' || str[i] == 'O' || str[i] == 'W'){
            if(model_str.find(segment) == -1) return;
            segment[0] = '\0';
        }
        else{
            strncat(segment, str+i, 1);
        }
    }

    for(int i = st; i <= ed; ++i){
        if(str[i] == 'O'){
            for(int j = st; j < i; ++j){
                if(str[j] == 'C'){
                    for(int k = ed; k > i; --k){
                        if(str[k] == 'W'){
                            char tem[80];
                            tem[0] = '\0';
                            strncat(tem, str, j);
                            strncat(tem, str+i+1, k-i-1);
                            strncat(tem, str+j+1, i-j-1);
                            strcat(tem, str+k+1);
                            DFS(tem, dep+1, st, ed);
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    freopen("cryptcow.in", "r", stdin);
    freopen("cryptcow.out", "w", stdout);

    cin.getline(ori,80);
    modellen = strlen(model);

    DFS(ori, 0, 0, strlen(ori)-1);

    if(!found) printf("0 0\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值