USACO 4.1 Cryptcowgraphy dfs+剪枝

这是一篇关于USACO比赛中4.1题Cryptcowgraphy的解题心得,作者分享了在解决这道涉及字符串处理和回溯剪枝的BT问题时所遇到的挑战。通过四种关键的剪枝技巧,包括字符计数一致性、字符串哈希判重、相邻字符匹配以及枚举顺序优化,最终成功解决问题。然而,作者承认自己在独立解决过程中遇到了困难,最终借助了他人的解题报告。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://ace.delos.com/usacoprob2?a=2SgXjKYaF1c&S=cryptcow

一道bt的剪枝题,做了一下午,最后还是看了别人的解题报告过的,才菜了。。 。

剪枝1:C,O,W出现的次数要相同,除了C,O,W之外的其他字符串的个数和类型和目标串相同。

剪枝2:通过ELFHash对串进行判重.( HASHSIZE可以大点)

剪枝3:对于任意串, 任意相邻的'C', 'O', 'W'之间的串应该在目标串中能找到.( 很强大的剪枝,没有这个剪枝就死活过不去。。)

剪枝4:枚举C,O,W的时候,先枚举O的位置,再枚举C,最后枚举W,而且W的枚举从后往前枚举。


代码:

/*
ID :chris
LANG :C++
TASK : cryptcow
*/
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
const int MAXM = 80 ;
string ch ;
string str = "Begin the Escape execution at the Break of Dawn" ;
int a1,a2,a3 ,len;
int num[300] ;
int stand[300] ;
int s_len  ;

void calc(){
	memset(stand , 0 ,sizeof(stand) );
	for(int i=0;str[i];i++){
		stand[ str[i] ] ++ ;
	}	
}
bool is_ok(){
	for(int i=0;i<300;i++)
		if(num[i] != stand[i])	return false ;
	return true ;
}
const int MAXN = 999991 ;
bool hash[MAXN];
bool f ;

int ELFhash(string ch){
	unsigned long h = 0; 
	for(int i=0;i<ch.size();i++){
		h = (h << 4) + ch[i] ;
		unsigned long g = h & 0xf0000000L ;
		if( g )
			h ^= g >> 24 ;
		h &= ~g ;
	}
	return h % MAXN ;
}

void dfs(string ch){
	if(ch == str){
		f = 1 ; return ;
	}
	int len = ch.size() ;
	string s ;
	for(int i=0;i<len;i++){
		if(ch[i] == 'C')	break ;
		if(str[i] != ch[i])	return ;
		if(ch[i]=='O' || ch[i]=='W')	return ;
	}
	int end = s_len - 1;
	for(int i=len-1;i>=0;i--){
		if(ch[i]=='W')	break ;
		if(ch[i] != str[end--])	return ;
		if(ch[i]=='O' || ch[i]=='C')	return  ;
	}
	int a = ELFhash(ch) ;
	if( hash[a] )	return ;
	hash[a] = 1 ;
	int cnt=0, c_cnt=0 ,o_cnt=0 , w_cnt=0; 
	int c[MAXM] ,o[MAXM] ,w[MAXM] ,label[MAXM] ;
	memset(c , 0,sizeof(c));
	memset(o , 0,sizeof(o));
	memset(w , 0,sizeof(w));
	memset(label , 0,sizeof(label));
	
	for(int i=0;i<len;i++){
		if( ch[i] == 'C'){
			c[c_cnt++] = i ;
			label[cnt++] = i ;
		}
		else if( ch[i]=='O'){
			o[o_cnt++] = i ;
			label[cnt++] = i ;
		}
		else if( ch[i]=='W'){
			w[w_cnt++] = i ;
			label[cnt++] = i ;
		}
	}
	label[ cnt++ ] = len ;
	for(int i=0;i<cnt-1;i++){
		if(label[i]+1 < label[i+1] ){
			string sub = ch.substr( label[i]+1 , label[i+1]-1-label[i]) ;
			if( str.find(sub) == string::npos){
				return ;
			}
		}
	}
	for(int i=0;i<o_cnt;i++){
		for(int j=0;j<c_cnt;j++){
			for(int k=w_cnt-1;k>=0;k--){
				if(c[j]<o[i] && o[i]<w[k]){
					string t1 = ch.substr(0,c[j]);
					string t2 = ch.substr(o[i]+1,w[k]-o[i]-1);
					string t3 = ch.substr(c[j]+1,o[i]-c[j]-1);
					string t4 = ch.substr(w[k]+1,len-w[k]);
					string t = t1+t2+t3+t4 ;
					dfs(t);
					if(f)	return ;
				}
			}
		}
		
	}
}
int main(){
	freopen("cryptcow.in","r",stdin);
	freopen("cryptcow.out","w",stdout);
	calc() ;
	s_len = str.size() ;
	getline(cin ,ch);
		a1 = a2 = a3 = 0 ;
		len = ch.size() ;
		memset(num , 0 ,sizeof(num));
		for(int i=0;i<len;i++){
			if(ch[i] == 'C')	a1 ++ ;
			else if(ch[i] == 'O')	a2 ++ ;
			else if(ch[i] == 'W')	a3 ++ ;
			else 	num[ ch[i] ] ++ ;
		}			
		if( is_ok() == 0){
			printf("0 0\n");return 0 ;
		}
		if(a1==0 && a2==0 && a3==0){
			if( ch == str )	printf("1 0\n");	
			else						printf("0 0\n");
			return 0 ;
		}
		if(a1==a2 && a2==a3){
			memset(hash , 0 ,sizeof(hash));
			f = 0 ;
			dfs(ch) ;
			if(f)	printf("1 %d\n",a1);
			else	printf("0 0\n");
		}
		else{
			printf("0 0\n");
		}
	return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值