USACO SECTION 4.1 Cryptcowgraphy

Cryptcowgraphy
Brian 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, say, "International Olympiad in Informatics", it is altered by inserting the letters C, O, and W, in random location in the message, such that C appears before O, which appears before W. Then the cows take the part of the message between C and O, and the part between O and W, and swap them. Here are two examples:

            International Olympiad in Informatics
                              -> 
            CnOIWternational Olympiad in Informatics
            
            International Olympiad in Informatics
                              -> 
            International Cin InformaticsOOlympiad W

To make matters more difficult, the cows can apply their encryption scheme several times, by again encrypting the string that results from the previous encryption. One night, Farmer John's cows receive such a multiply-encrypted message. Write a program to compute whether or not the non-encrypted original message could have been the string:

            Begin the Escape execution at the Break of Dawn

PROGRAM NAME: cryptcow

INPUT FORMAT

A single line (with both upper and lower case) with no more than 75 characters that represents the encrypted message.

SAMPLE INPUT (file cryptcow.in)

Begin the EscCution at the BreOape execWak of Dawn

OUTPUT FORMAT

Two integers on a single line. The first integer is 1 if the message decodes as an escape message; 0 otherwise. The second integer specifies the number of encryptions that were applied (or 0 if the first integer was 0).

SAMPLE OUTPUT (file cryptcow.out)

1 1

 

/*
ID: conicoc1
LANG: C
TASK: cryptcow
*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define Min(a,b) a>b?b:a

char Cow[76];
int CowCount=0;
char *GoalCow="Begin the Escape execution at the Break of Dawn\0";
int flag[1000003];

unsigned long long int Hash()
{
  	unsigned long long int seed=131313,hash=0;
    int i=0;
    while(Cow[i]!='\0') 
		hash=hash*seed+Cow[i++];
//	printf("%lld\n",(hash & 0x7FFFFFFF) % 1000003);
    return (hash & 0x7FFFFFFF) % 1000003;
}

int Judge1()
{
	int i=0,j=0,start;
	while(Cow[i]!='\0'){
		while(Cow[i]=='C'||Cow[i]=='O'||Cow[i]=='W')
			i++;
		start=i;
		j=0;
		while(Cow[i]!='C'&&Cow[i]!='O'&&Cow[i]!='W'&&Cow[i]!='\0'){
			if(Cow[i]!=GoalCow[j]){
				j++;
				i=start;
				if(GoalCow[j]=='\0'){
					return 0;
				}
			}
			else{
				i++;
				j++;
			}
		}		
	}
	return 1;
}

int Judge2()
{
	int i;
	int C=0,O=0,W=0;
	for(i=0;Cow[i]!='\0';i++){
		if(Cow[i]=='C')
			C++;
		if(Cow[i]=='O')
			O++;
		if(Cow[i]=='W')
			W++;
	}	
	if(C!=O||O!=W||C!=W)	
		return 1;
	return 0;
}

void SwapCow(int i,int j,int k)
{
	char temp1[76],temp2[76],temp3[76];
	int Pos;
	for(Pos=0;Pos<j-i-1;Pos++)
		temp1[Pos]=Cow[i+Pos+1];
	temp1[Pos]='\0';
	for(Pos=0;Pos<k-j-1;Pos++)
		temp2[Pos]=Cow[j+Pos+1];
	temp2[Pos]='\0';
	for(Pos=0;Pos<strlen(Cow)-k;Pos++)
		temp3[Pos]=Cow[k+Pos+1];
	temp3[Pos]='\0';
	strcpy(Cow+i,temp2);
	strcpy(Cow+strlen(Cow),temp1);
	strcpy(Cow+strlen(Cow),temp3);
}

int DFS()
{
	int i,j,k;
	char TmpCow[76];
	if(strcmp(Cow,GoalCow)==0)
		return 1;
	/************剪枝1************/
	for(i=0;Cow[i]!='\0';i++)
		if(Cow[i]!=GoalCow[i]){
			if(Cow[i]!='C')
				return 0;
		    break; 
		}
	/*************剪枝2***********/
	if(!Judge1())
		return 0;
	/*************剪枝3***********/
	if(flag[Hash()])
		return 0;
	else
		flag[Hash()]=1; 
	strcpy(TmpCow,Cow);
//	printf("%s\n",Cow);
	for(i=0;Cow[i]!='\0';i++){
		if(Cow[i]!='C')
			continue;
		for(j=i;Cow[j]!='\0';j++){
			if(Cow[j]!='O')
				continue;
			for(k=j;Cow[k]!='\0';k++){
				if(Cow[k]!='W')
					continue;
				SwapCow(i,j,k);
				if(DFS())
					return 1;
				else
					strcpy(Cow,TmpCow);
			}
		}
	}

	return 0;
}

int main()
{
	FILE *fin,*fout;
	fin=fopen("cryptcow.in","r");
	fout=fopen("cryptcow.out","w");
	memset(flag,0,sizeof(flag));
	char c;
	int i=0,j=0,Count=0;
	while(fscanf(fin,"%c",&c)!=EOF){
		if(c=='\n')
			continue;
		Cow[CowCount++]=c;
		if(c=='C'||c=='O'||c=='W')
			Count++;
	}
  	if(!Judge2()&&DFS())
		fprintf(fout,"1 %d\n",Count/3);
	else
		fprintf(fout,"0 0\n");
	return 0;
}


一道略变态的搜索题。。。

那个ELFHASH完全不知道什么原理,感觉就是乱搞一气。。。然后判重。

 

一些优化技巧复制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倍左右。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值