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

来源:互联网 发布:linux如何关闭防火墙 编辑:程序博客网 时间:2024/05/16 10:33


   开始做的时候就想到是搜索...写完了样例就跑过了..然后提交就超时..后来再一想..裸搜时间复杂度高得惊人阿..做了几个优化..还是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))*2using 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;     } 


原创粉丝点击