Cryptcowgraphy

dfs搜索+剪枝

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 char fin[48];
  5 char a[80];
  6 int atop=0;
  7 char c;
  8 int cnt;
  9 int vis[1000010];
 10 struct point
 11 {
 12     char s[80];
 13     int cur;
 14 } p;
 15 int init(char *str)
 16 {
 17     int len=strlen(str);
 18     int left=0;
 19     int right;
 20     while(left<len)
 21     {
 22         while(str[left]==‘C‘||str[left]==‘O‘||str[left]==‘W‘)
 23         {
 24             left++;
 25         }
 26         if(left==atop) return 0;
 27         right=left;
 28         while(str[right]!=‘C‘&&str[right]!=‘O‘&&str[right]!=‘W‘&&str[right])
 29         {
 30             right++;
 31         }
 32         if(right-left>47) return 1;
 33         int sign=0;
 34         for(int i=0; i<48-right+left; i++)
 35         {
 36             int sign1=1;
 37             for(int j=left; j<right; j++)
 38             {
 39                 if(str[j]!=fin[i+j-left])
 40                 {
 41                     sign1=0;
 42                     break;
 43                 }
 44             }
 45             if(sign1)
 46             {
 47                 sign=1;
 48                 break;
 49             }
 50         }
 51         if(sign==0) return 1;
 52         left=right;
 53     }
 54     return 0;
 55 }
 56 unsigned int BKDRHash(char *str)
 57 {
 58     unsigned int seed = 131;
 59     unsigned int hash = 0;
 60     while (*str)
 61     {
 62         hash = hash * seed + (*str++);
 63     }
 64     return hash%1000007;
 65 }
 66 int dfs(point pp)
 67 {
 68     if(pp.cur==cnt)
 69     {
 70         if(strcmp(pp.s,fin)==0) return 1;
 71         else return 0;
 72     }
 73     int len=47+(cnt-pp.cur)*3;
 74     int c[20],o[20],w[20];
 75     int ctop=0,otop=0,wtop=0;
 76     for(int i=0; i<len; i++)
 77     {
 78         if(pp.s[i]==‘C‘) c[ctop++]=i;
 79         if(pp.s[i]==‘O‘) o[otop++]=i;
 80         if(pp.s[i]==‘W‘) w[wtop++]=i;
 81     }
 82     if(w[wtop-1]<o[otop-1]||w[wtop-1]<c[ctop-1]) return 0;
 83     if(c[0]>o[0]||c[0]>w[0]) return 0;
 84     for(int i=0;i<c[0];i++)
 85     {
 86         if(pp.s[i]!=fin[i]) return 0;
 87     }
 88     if(ctop!=otop||ctop!=wtop) return 0;
 89     if(init(pp.s)) return 0;
 90     for(int i=0; i<otop; i++)
 91     {
 92         for(int j=wtop-1; w[j]>o[i]&&j>=0; j--)
 93         {
 94             for(int k=0; c[k]<o[i]&&k<ctop; k++)
 95             {
 96                 int cwei=c[k];
 97                 int owei=o[i];
 98                 int wwei=w[j];
 99                 point p1;
100                 int p1top=0;
101                 p1.cur=pp.cur+1;
102                 for(int i=0; i<cwei; i++)
103                 {
104                     p1.s[p1top++]=pp.s[i];
105                 }
106                 for(int i=owei+1; i<wwei; i++)
107                 {
108                     p1.s[p1top++]=pp.s[i];
109                 }
110                 for(int i=cwei+1; i<owei; i++)
111                 {
112                     p1.s[p1top++]=pp.s[i];
113                 }
114                 for(int i=wwei+1; i<len; i++)
115                 {
116                     p1.s[p1top++]=pp.s[i];
117                 }
118                 p1.s[p1top]=0;
119                 int temp=BKDRHash(p1.s);
120                 if(vis[temp]==0)
121                 {
122                     vis[temp]=1;
123                     if(dfs(p1)) return 1;
124                 }
125             }
126         }
127     }
128     return 0;
129 }
130 int main()
131 {
132     memset(vis,0,sizeof(vis));
133     strcpy(fin,"Begin the Escape execution at the Break of Dawn");
134     while(scanf("%c",&c)!=EOF)
135     {
136         if(c!=‘\n‘)
137             a[atop++]=c;
138     }
139     a[atop]=0;
140     if(atop<47||(atop-47)%3)
141     {
142         printf("0 0\n");
143     }
144     else
145     {
146         cnt=(atop-47)/3;
147         strcpy(p.s,a);
148         p.cur=0;
149         if(dfs(p)) printf("1 %d\n",cnt);
150         else printf("0 0\n");
151     }
152     return 0;
153 }

剪枝: (from nocow)

  1. 由于添加的COW是一起的,因此给出的字符串的字符个数应该等于47(目标字符串的长度)+3*k。如果不满足就可直接判断无解。
  2. 除了COW三个字符外,其他的字符的个数应该和目标串相一致。如果不一致也可直接判断无解。
  3. 搜索中间肯定会出现很多相同的情况,因此需要开一个hash来记录搜索到过哪些字符串,每搜索到一个字符串,就判重。如果重复直接剪枝。这里的字符串的hash函数可以采用ELFhash,但由于ELFhash的数值太大,所以用函数值对一个大质数(我用的是99991)取余,这样可以避免hash开得太大,同时又可以减少冲突。
  4. 对搜索到的字符串,设不包含COW的最长前缀为n前缀(同样也可以定义n后缀),那么如果n前缀不等于目标串的长度相同的前缀,那么当前字符串一定无解,剪枝。N后缀也可采取相同的判断方法。
  5. 一个有解的字符串中,COW三个字母最早出现的应该是C,最后出现的应该是W,如果不满足则剪枝。
  6. 当前字符串中任意两个相邻的COW字母中间所夹的字符串一定在目标串中出现过。如果不符合可立即剪枝。
  7. 需要优化搜索顺序。经过试验我们可以发现,O的位置对于整个COW至关重要。可以说,O的位置决定了整个串是否会有解。因此,我们在搜索时,应该先枚举O的位置,然后再枚举C和W的位置。其中W要倒序枚举。这样比依次枚举COW至少要快20~30倍。
  8. 在判断当前串的子串是否包含在目标串中的时候,可以先做一个预处理:记录每一个字母曾经出现过的位置,然后可以直接枚举子串的第一个字母的位置。这样比用pos要快2倍左右。
时间: 2024-11-03 20:46:46

Cryptcowgraphy的相关文章

USACO 6.3 Cryptcowgraphy

CryptcowgraphyBrian Dean The cows of Farmer Brown and Farmer John are planning a coordinated escape from their respective farms and have devised a method of encryption to protect their written communications. Specifically, if one cow has a message, s

【CodeVS 2083】Cryptcowgraphy 解密牛语

http://codevs.cn/problem/2083/ 奶牛搜索题.我加了如下剪枝: 1.用字符串hash判重.注意判重时也要对字符串长度判重,否则会出现两个字符串长度不同但hash值相同的情况,非常容易被卡hash. 2.先枚举O,再枚举C,W.枚举W时从后往前枚举.从网上的题解里看到的,具体为什么我也不知道(捂脸). 3.对于所有的C,O,W字母可以将字符串切成好几段,但是无论我们怎么交换C-O之间和O-W之间的字符串,这些小段字符串是不会被分开的.所以对于每一个状态我们判断所有C,O

[USACO 6.3.2] Cryptcowgraphy

题目大意 现在知道一个字符串"Begin the Escape execution at the Break of Dawn",在其中按顺序插入'C','O','W'.'C'和'O'之间的部分会和'O''W'之间的部分调换. 给一个字符串,问此字符串是不是又上述变换形成的并输出经历多少次变换. 题解 这是黑书<<算法艺术与信息学竞赛>>中的一道搜索题. 很明显,如果朴素的算法是不可能AC的.因此,我们要加入一些优化. 1.搜索顺序: 听说加入这个剪枝也是会快不少

一次愚蠢的NOIP模拟赛

找礼物[find.pas/find.c/find.cpp] [问题描述] 新年到了,突然间,就在那美丽的一霎那,你好友和你(K个人)的周围满是礼物,你发扬你帅气的风格,让你的好友先拿,但是每个人只能拿当前离自己最近的礼物[当然如果有并列的多个礼物离你的距离相等(精确到小数后四位,所有运算均为去尾),这些礼物就都属于这个人].现在你们所在的位置是原点(0,0),每个礼物的位置用坐标表示.现在告诉你每个礼物的坐标,还有每个礼物是谁送的.要你找出你的礼物离你多远,你能拿到多少礼物,这些礼物是谁送的.如

USACO 6.2 章节 你对搜索和剪枝一无所知QAQ

Fence Rails 题目大意 N<=50个数A1,A2... 1023个数,每个数数值<=128,B 问 A 们能拆分成多少个B,求最多的个数 样例 解释 A: 30=30 40=18+19+3 50=15+16+17+2 25=24 B: 15 (ok) 16 (ok) 17 (ok) 18 (ok) 19 (ok) 20 21 25 24 (ok) 30 (ok) 所以最多7个 题解 首先 如果对B 排序,假设最优个数为k个 显然 如果k个可行,那么排序后的B 的前k个可行 又 如果k