USACO Section 4.1 Cryptcowgraphy - BT的DFS剪枝..

24 篇文章 0 订阅


   开始做的时候就想到是搜索...写完了样例就跑过了..然后提交就超时..后来再一想..裸搜时间复杂度高得惊人阿..做了几个优化..还是N久跑不出结果...我以为搜索是搜不过的...就想用其他方法来解决..但纠结了很久也没有个明确方向..
   写了一天..实在是没辙了..就去网上搜了下解题报告..发现其实是搜索~~关键还是在于剪枝~~~我原来的搜索剪枝真是弱爆了..
          1.C.O.W这三个字符任意两个中间的无C.O.W的字符串一定要是原串的子串才合法..因为在后面做任何变化这一段都是改变不了的了.. 
          2.差不多和上面那个一个意思..就是最前面没有任何C.O.W的一截必须和原串的前面这截相等..尾部一样..同上理.. 
          3.C.O.W这些字符出现在最左边的一定是C,出现在最右边的一定是W.. 
          4.在DFS过程中会有很多重复的搜索..这里就要通过Hash来判重..我的Hash方法..见我的Turn函数..自创的说.. 
          5.很诡异的..在别人那看到的..想不出有什么道理..但却是速度提升很多..或许是题目数据的特殊所至~~
             先确定O..再确定C..再确定W...在确定W时从后往前扫~~ 
   还有就是字符串用char[]来处理比string来处理速度至少快3倍阿~~ 
   这道题用了几个以前很少用到的字符串函数,这次也熟悉了下...如
          strcmp(s1,s2)是比较两串..当且仅当strcmp的返回值是0的时候s1与s2相等... 
         strncat(s1,s2,k)将s2的前k位加到s1的后面..如果要中间的一段..strncat(s1,s2+i,j)就行了  

Program:

/*  
ID: zzyzzy12   
LANG: C++   
TASK: cryptcow
*/      
#include<iostream>      
#include<istream>  
#include<stdio.h>      
#include<string.h>      
#include<math.h>      
#include<stack>
#include<map>
#include<algorithm>      
#include<queue>   
#define oo 2000000000  
#define ll long long  
#define pi (atan(2)+atan(0.5))*2
using namespace std;    
char str[50]="Begin the Escape execution at the Break of Dawn",s[305];
int lenstr=strlen(str),x,Prime[505],num; 
string ss1=str;
bool f,hash[500005];
int Turn(char *s)
{
      int i,k=0,l=strlen(s);
      s[l]='a';
      for (i=0;i<l;i++)
      {
           k+=Prime[i+1]*s[i]*(s[i]+s[i+1]);
           k%=500000;
      }
      s[l]='\0';
      return k;  
}   
void DFS(char *s,int p)
{      
      int i,j,k,t,l=strlen(s); 
      char s1[305];
      x=Turn(s);
      if (hash[x]) return;
      hash[x]=true;      
      if (!strcmp(s,str))
      {
             f=true;
             printf("1 %d\n",p); 
             return;           
      }      
      //-------------------判断末尾一截是否相等------------------
      t=lenstr; i=l;
      while (s[i]!='C' && s[i]!='O' && s[i]!='W')
      {
             if (s[i]!=str[t]) return; 
             t--;  i--;   
      } 
      if (s[i]!='W') return; 
      //------------------判断前面一截是否相等-------------------
      i=0;
      while (s[i]!='C' && s[i]!='O' && s[i]!='W')
      {
             if (s[i]!=str[i]) return;
             i++;      
      }
      if (s[i]!='C') return;
      //-------------判断C,O,W中间的串是否在所求串中存在---------
      s1[0]='\0';
      for (i++;i<l;i++)
      if (s[i]=='C' || s[i]=='O' || s[i]=='W')
      {               
             if (ss1.find(s1)==-1) return; 
             s1[0]='\0'; 
      }else strncat(s1,s+i,1); 
      //----------------------------------------- 
      for (j=0;j<l;j++)
          if (s[j]=='O')
              for (i=0;i<j;i++)
                 if (s[i]=='C')  
                     for (k=l-1;k>j;k--)
                         if (s[k]=='W')
                         {      
                                 s1[0]='\0';
                                 strncat(s1,s,i); 
                                 strncat(s1,s+j+1,k-j-1); 
                                 strncat(s1,s+i+1,j-i-1); 
                                 strncat(s1,s+k+1,l-k-1);  
                                 DFS(s1,p+1);      
                                 if (f) return; 
                         }     
}
int main()  
{  
      freopen("cryptcow.in","r",stdin);   
      freopen("cryptcow.out","w",stdout); 
      gets(s);
      while (s[strlen(s)-1]==' ') s[strlen(s)-1]='\0'; 
      f=false;
      memset(hash,false,sizeof(hash));
      num=0;
      for (int i=3;i>0;i++)
      {
            for (int j=2;j*j<=i;j++)
               if (i%j==0) goto A;
            Prime[++num]=i;
            if (num==500) break;   
            A: ;          
      }
      DFS(s,0);
      if (!f) printf("0 0\n"); 
      return 0;     
} 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值