您的位置:首页 > 其它

usaco 4.1 Cryptcowgraphy 剪枝

2008-08-21 22:55 197 查看
这道题目需要大量优化,要用到ELFhash字符串哈希,空间不能开太大,否则会很慢,但是在我的机器上试,空间不影响速度,有可能是因为usaco服务器的问题
总结一下错误的地方
1)下标错误:把c,o,w搞混了
2)边界错误:对于字符数组,需要判断0<=i && i < n,一般在有+-的时候容易出错,更一般的,加法和乘法注意溢出,减法注意负数,除法注意除数为0的情况

优化措施总结如下

1)字符串的字符个数应该等于(目标字符串的长度)+3*k。如果不满足就可直接判断无解。
2)除了COW三个字符外,其他的字符的个数应该和目标串相一致。如果不一致也可直接判断无解。前两项都可以在搜索前进行 .
3)搜索中间肯定会出现很多字符串相同的情况,因此需要开一个hash来判断是否搜索过,用ELFhash可以对字符串很好的处理 ,这里哈希数组大小为131071
4)一个有解的字符串中,COW三个字母最早出现的应该是C,最后出现的应该是W,如果不满足则剪枝。
5)当前字符串被COW分为几个子串,每个子串一定也是目标串的子串,如果不符合可立即剪枝, 也可以用hash来存储。
6)需要优化搜索顺序。先枚举O,并且W要逆序枚举

经过上述优化,程序对于极端数据也可以在1s以内出解。

以下是我的代码

#include <iostream>

#include <algorithm>

#include <string>

#include <map>

using namespace std;

/*

PROG: cryptcow

LANG: C++

ID: heben991

*/

const int N = 80, M = 256, D = 80, hash_size = 131071;

// too large hash_size will be slow!!

char code
= "Begin the Escape execution at the Break of Dawn";

int len = strlen(code);

int code_cnt[M], str_cnt[M];

char s[D]
, ss
, *p, ch, cow[5]="COW";

bool hash[hash_size], code_hash[hash_size];

int ELFhash(char *key)

{

unsigned long h=0,g;

while(*key)

{

h=(h<<4) + *key++;

g=h & 0xF0000000L;

if(g) h^= g>>24;

h &= ~g;

}

return h % hash_size;

}

bool impossible(char *s, int n)

{

int i=0, j, c, w;

for(c = 0; c < n && s[c]!='C'; ++c);

for(w = n-1; w >=0 && s[w]!='W'; --w);

if(c < n && w >= 0 && c >= w)return true;

strcpy(ss,s);

p = strtok(ss,cow);

while(p)

{

if(!code_hash[ELFhash(p)])return true;

p = strtok(0,cow);

}

return false;

}

bool ok(int deep, int n)

{

int i, t, c, o, w;

if(strcmp(s[deep],code)==0)

{

return true;

}

if(n<=len)return false;

t = ELFhash(s[deep]);

if(!hash[t]) hash[t]=true;

else return false;

if(impossible(s[deep],n)) return false;

s[deep+1][n-3] = 0;

for(o = 1; o < n-1; ++o)

if(s[deep][o]=='O')

{

for(c = 0; c < o; ++c)

{

if(c>0) s[deep+1][c-1] = s[deep][c-1];

if(s[deep][c]=='C')

for(w = n-1; w > o; --w)

{

if(w<n-1 && w-2>=0) s[deep+1][w-2] = s[deep][w+1];

// hint: if(w<n-1 && w-2>=0) w-2!!

if(s[deep][w]=='W')

{

t = c;

for(i = o+1; i < w; ++i) s[deep+1][t++] = s[deep][i];

for(i = c+1; i < o; ++i) s[deep+1][t++] = s[deep][i];

if( ok(deep+1,n-3) ) return true;

}

}

}

}

return false;

}

bool all_in_code(char *s, int n)

{

int i, j;

for(i = len-1; i >= 0; --i)

{

for(j = i+1; j <= len; ++j)

{

ch = code[j];

code[j] = 0;

code_hash[ELFhash(code+i)] = true;

code[j] = ch;

}

}

for(i = 0; i < n; ++i) str_cnt[s[i]]++;

for(i = 0; i < len; ++i) code_cnt[code[i]]++;

for(ch = 'A'; ch <= 'z'; ++ch)

if(ch!='C' && ch!='O' && ch!='W' && code_cnt[ch]!=str_cnt[ch])

{

printf("%c %d %d/n", ch, code_cnt[ch],str_cnt[ch]);

return 0;

}

return 1;

}

int main()

{

int n;

freopen("cryptcow.in", "r", stdin);

freopen("cryptcow.out","w",stdout);

gets(s[0]);

n = strlen(s[0]);

if( (n-len)%3==0 && all_in_code(s[0],n) && ok(0,n) )

{

int ans=0;

for(p=s[0];*p;++p) if(*p=='C')++ans;

printf("%d %d/n", 1,ans);

}

else puts("0 0");

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: