usaco 4.1 Cryptcowgraphy(DFS+hash+剪枝)

本文介绍了牛信加密技术,这是一种通过插入特定字母并交换部分字符串来加密消息的方法。为了应对多次加密的消息,需要编写程序来判断原始未加密消息是否可能为给定字符串。该问题解决方案采用深度优先搜索(DFS)配合哈希表进行剪枝优化,通过判断哈希表中的状态来避免无效计算,提高效率。

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

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
题目: http://ace.delos.com/usacoprob2?a=3VP4hdY1ws8&S=cryptcow

题意:给你一个字符串,要你去掉 C O W,这三个字母的同时,把C O和O W所包含的字符串对调,使得最后字符串成为题目所求

分析:这题很明显只能搜索了,不过肯定要剪枝,这种时候其实最早想到的应该是hash判重,我居然没想到,估计是太久没做题了,然后就是各种跟题目相关的剪枝,明显无解的情况都要去掉,具体就不说了,还有剪枝的顺序不同,造成的结果也是不同的这个让我爆内存n次。。。不过因此用了一个土办法,居然速度比正解快好多,hash真是个神奇的东西(就是如果hash表满了,就不保存剩下的所有状态,这样居然做到每组都是0.1S左右)=  =

代码(不会爆内存的写法,爆内存那种就不贴出来了):

/*
ID: 15114582
PROG: cryptcow
LANG: C++
*/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mm=100007;
struct hashtable
{
    int h[mm],p[mm],size;
    char s[mm][77];
    int chash(char *a)
    {
        int ch=0;
        while(*a)ch=ch*131+(*a++);
        return (ch&0x7FFFFFFF)%mm;
    }
    int insert(char *a)
    {
        int i,ch=chash(a);
        for(i=h[ch];i>=0;i=p[i])
            if(!strcmp(s[i],a))
                return 1;
        strcpy(s[size],a);
        p[size]=h[ch],h[ch]=size++;
        return 0;
    }
    int find(char *a)
    {
        int i,ch=chash(a);
        for(i=h[ch];i>=0;i=p[i])
            if(!strcmp(s[i],a))
                return 1;
        return 0;
    }
    void clear()
    {
        size=0;
        memset(h,-1,sizeof(h));
    }
}g;
char c[77],s[77];
char ans[]="Begin the Escape execution at the Break of Dawn";
bool check()
{
    int i,j,k,len=strlen(s);
    for(i=0;i<len;++i)
        if(s[i]=='C'||s[i]=='O'||s[i]=='W')break;
    if(s[i]!='C')return 1;
    for(i=len-1;i>=0;--i)
        if(s[i]=='C'||s[i]=='O'||s[i]=='W')break;
    if(s[i]!='W')return 1;
    for(i=0;i<len;++i)
        if(s[i]!='C'&&s[i]!='O'&&s[i]!='W')
        {
            for(j=i+1;j<len;++j)
                if(s[j]=='C'||s[j]=='O'||s[j]=='W')break;
            k=0;
            while(i<j)c[k++]=s[i++];
            c[k]='\0';
            if(!g.find(c))return 1;
        }
    return 0;
}
bool dfs(int t)
{
    if(t<1)
    {
        if(!strcmp(ans,s))return 1;
        return 0;
    }
    int i,j,k,r,p,len=strlen(s);
    char c[77];
    strcpy(c,s);
    for(i=0;i<len;++i)
        if(c[i]=='O')
            for(j=len-1;j>i;--j)
                if(c[j]=='W')
                    for(k=0;k<i;++k)
                        if(c[k]=='C')
                        {
                            for(r=p=0;r<k;++r,++p)s[p]=c[r];
                            for(r=i+1;r<j;++r,++p)s[p]=c[r];
                            for(r=k+1;r<i;++r,++p)s[p]=c[r];
                            for(r=j+1;r<len;++r,++p)s[p]=c[r];
                            s[p]='\0';
                            if(!strcmp(ans,s))return 1;
                            if(check()||g.insert(s))continue;
                            if(dfs(t-1))return 1;
                        }
    return 0;
}
int main()
{char c[77];
    freopen("cryptcow.in","r",stdin);
    freopen("cryptcow.out","w",stdout);
    int i,j,k,s1,s2,s3;
    while(gets(s))
    {
        for(s1=s2=s3=i=0;i<strlen(s);++i)
        {
            if(s[i]=='C')++s1;
            if(s[i]=='O')++s2;
            if(s[i]=='W')++s3;
        }
        g.clear();
        for(i=0;i<strlen(ans);++i)
            for(j=i,k=0;j<strlen(ans);++j,++k)
            {
                if(j-i+1>=strlen(ans))break;
                c[k]=ans[j];
                c[k+1]='\0';
                g.insert(c);
            }
        g.insert(s);
        if(s1+s2+s3==strlen(s)-strlen(ans)&&s1==s2&&s2==s3&&dfs(s1))printf("%d %d\n",1,s1);
        else puts("0 0");
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值