您的位置:首页 > 其它

[USACO4.1.4 Cryptcowgraphy]

2012-03-03 18:22 232 查看
[关键字]:搜索 剪枝

[题目大意]:有一种加密方式:在一个字符串中加入‘C’‘O’‘W’,并把‘C’和‘O’中间的字符和‘O’和‘W’之间的字符交换,给出一个字符串,看是否是“Begin the Escape execution at the Break of Dawn ”经过加密(有可能多次加密)。

//===============================================================================================

[分析]:搜索题但是剪枝很恶心,每次都找一组C、O、W然后解密继续找直到找完所有情况或找到目标。有如下几个剪枝加上后基本可以在0.5s左右过:

1、如果给出串长度不是47(目标长度)+3*k,或各个字符与目标串出现的次数不符,则可判定无解。

2、利用Hash表保存已经查找过的状态。这里貌似有个Bug——hash不用处理冲突(小数据无冲突,大数据都无解),否则有可能超时。(主要)

3、每次判断第一个C前面和最后一个W后面的字符是否和目标串一样。(主要)

4、C、O、W两两之间的子串应改都能在目标串中找到。(主要)

5、每次找O,再在O的两边分别找C和W。(主要)

[代码]:

View Code

/*
ID:procedure2
PROB:cryptcow
LANG: C++
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const char goal[]={"Begin the Escape execution at the Break of Dawn"};

char s[100];
int b[200],ans;
bool flag=0;
bool h[1100000];
char ch;

unsigned long Hash(char *s)
{
int len=strlen(s);
unsigned long hash=0,seek=131313;
for (int i=0;i<len;i++) hash=hash*seek+s[i];
hash=(hash&0x7fffffff)%1000003;
return hash;
}

void Change(char *s,int c,int  o,int w)
{
char s2[100];
memset(s2,0,sizeof(s2));
int len=0;
for (int i=0;i<c;i++)
s2[len++]=s[i];
for (int i=o+1;i<w;i++)
s2[len++]=s[i];
for (int i=c+1;i<o;i++)
s2[len++]=s[i];
for (int i=w+1;i<strlen(s);i++)
s2[len++]=s[i];
strcpy(s,s2);
}

bool Cleck(char *s)
{
//printf("%s\n",s);
int len=strlen(s),ls,lg=strlen(goal);
long  t=Hash(s);
if (h[t]) return 0; else h[t]=1;
for (int i=0;i<len;i++)
if (s[i]!='C')
{if (s[i]!=goal[i]) return 0;}
else {ls=i+1;break;}
for (int i=len-1;i>=0;i--)
if (s[i]!='W')
{if (s[i]!=goal[--lg]) return 0;}
else {lg=i;break;}
//=============================
int i=ls,j=0;
char s2[100];
//printf("%d %d\n",ls,lg);
while (i<=lg)
{
memset(s2,0,sizeof(s2));
while (i<lg && s[i]!='C' && s[i]!='O' && s[i]!='W') s2[j++]=s[i++];
//printf("%s\n",s2);
if (i<=lg)
if (!strstr(goal,s2)) return 0;
i++,j=0;
}
return 1;
}

void DFS(int now,char *s)
{
if (strcmp(s,goal)==0) {ans=now,flag=1;return;}
if (!Cleck(s)) return;
int ls=strlen(s);
char s1[100];
for (int j=0;j<ls;j++)
if (s[j]=='O')
for (int i=0;i<j;i++)
if (s[i]=='C')
for (int k=j+1;k<ls;k++)
if (s[k]=='W')
{
//printf("%d %d %d\n",i,j,k);
strcpy(s1,s);
Change(s1,i,j,k);
DFS(now+1,s1);
if (flag) return;
}
}

int main()
{
freopen("cryptcow.in","r",stdin);
freopen("cryptcow.out","w",stdout);
gets(s);
int ls=strlen(s);
if (s[ls-1]=='\n') s[ls-1]='\0';
//printf("%c\n",s[ls-2]);
//if (strcmp(s,goal)==0) {printf("1 0\n"); return 0;}
ls=strlen(s);
memset(b,0,sizeof(b));
if ((ls-47)%3!=0 && !strcmp(s,goal)) {printf("0 0\n"); return 0;};
//printf("%s*\n%s&",s,goal);
int lg=strlen(goal);
for (int i=0;i<lg;i++) b[goal[i]]++;
for (int i=0;i<ls;i++)
if (s[i]!='C' && s[i]!='O' && s[i]!='W') b[s[i]]--;
for (int i=0;i<100;i++) if (b[i]!=0) {printf("0 0\n"); return 0;}
DFS(0,s);
if (flag) printf("1 %d\n",ans); else printf("0 0\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: