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;
}