您的位置:首页 > 其它

URAL1002 PHONE NUMBER

2015-06-08 17:22 190 查看
题意很简单啦,,就像手机键盘,一个数字代表几个字母,问给一串数字,给几个单词,问数字能不能打出下面的几个单词(不用全打),一看就是dp嘛~当然我先用的暴力的做法(懒),明知道有问题就是想测测oj的数据233333(暴力就是直接循环数字串一个字母匹配上了就看剩下的能不能匹配上,能的话这个词就留下,匹配剩下的,有一个数字谁也打不出来就算匹配不上——错误是显而易见的,有的时候后面需要这个词却在前面匹配上了导致后面的匹配不上,,,,,,,)

WA代码:

#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cstring>

using namespace std;

char s[50001][51];

int b[50001][51];

char a1[100001];

int a[100001];

char q[50001][51];

void zhuanhuan(int i)

{

    int j;

    for(j=0;j<strlen(s[i]);j++)

    {

        if(s[i][j]=='i'||s[i][j]=='j') b[i][j]=1;

        if(s[i][j]=='a'||s[i][j]=='b'||s[i][j]=='c') b[i][j]=2;

        if(s[i][j]=='d'||s[i][j]=='e'||s[i][j]=='f') b[i][j]=3;

        if(s[i][j]=='g'||s[i][j]=='h') b[i][j]=4;

        if(s[i][j]=='k'||s[i][j]=='l') b[i][j]=5;

        if(s[i][j]=='m'||s[i][j]=='n') b[i][j]=6;

        if(s[i][j]=='p'||s[i][j]=='r'||s[i][j]=='s') b[i][j]=7;

        if(s[i][j]=='t'||s[i][j]=='u'||s[i][j]=='v') b[i][j]=8;

        if(s[i][j]=='w'||s[i][j]=='x'||s[i][j]=='y') b[i][j]=9;

        if(s[i][j]=='o'||s[i][j]=='q'||s[i][j]=='z') b[i][j]=0;

    }

}

int main()

{

    while(scanf("%s",a1)!=EOF)

    {

        memset(s,0,sizeof(s));

        memset(b,0,sizeof(b));

        if(a1[0]=='-') break;

        int m;

        scanf("%d",&m);

        int i,j,k;

        int t=0;

        int glag=0,flag=0;

        for(i=0;i<m;i++)

        {

            scanf("%s",&s[i]);

            zhuanhuan(i);

        }

        int len=strlen(a1);

        for(i=0;i<len;i++) a[i]=a1[i]-'0';

        for(i=0;i<len;i++)

        {

            //printf("i = %d\n",i);

            for(j=0;j<m;j++)

            {

                if(a[i]==b[j][0])

                {

                    for(k=1;k<strlen(s[j]);k++)

                    {

                        if(b[j][k]!=a[i+k]) break;

                        //printf("k=%d\n",k);

                    }

                    if(k==strlen(s[j]))

                    {   //printf("*");

                        flag=1;

                        strcpy(q[t],s[j]);

                        t++;

                        break;

                    }

                }

            }

            if(flag==1)

                {

                    i=i+k-1;

                    flag=0;

                }

            else {glag=1; break;}

        }

        if(glag==1) printf("No solution.\n");

        else

        {

            for(i=0;i<=t;i++)

            {

                if(i!=0) printf(" ");

                printf("%s",q[i]);

            }

            printf("\n");

        }

    }

    return 0;

}

(以上完全是占篇幅并没有什么卵用)

这题说实话一开始并没有什么好的DP想法,DP这种东西我觉得不是学了背包什么最长公共字串就能任意写方程了,,,,觉得还是做题的数量还有脑力的问题吧,,,,哎,,还是要加油,,,这题是先看的别人的HINT,然后自己敲的,是这样的:

不想先写代码再解释因为我知道有的人只想看HINT,,,,,,解释一下,,就是如果数字i和数字j之间有单词k,我们就让w[i,j]=1(后面会说到等于单词第K个),这样就有了dp方程//呵呵这里最关键了我看了好多文章都是直接给这个不说为什么,,妈蛋!!我决定不找到为什么就不发这篇。。。

if(w[j][i]!=0)

                {

                    dp[i+j]=min(dp[i],dp[j]+1);

                    //printf("*\n");

                }                                                 //比较的是到i之前有几个单词,,,如果之前用的单词就比较少就不用换了。。。。。。重点就是这里!!!要将dp[0]初始化为0,这样如果有一个从0开始的单词,那么dp[0+j]就绝对会是1了,,,然后只有有一个单词可以用首和这个相连(或者与0相连),才会有2或者第一个1,最后如果能到最后一个才是真正的可以完成。。。。问题来了,,如果这个不是dp[j]+1而是直接写成1来标记行不行?自然是可以的!!!只是不是最优的条件(题里说都可以),,所以,,嘿嘿,,路漫漫兮其修远啊,,,,想了好久好久。。。。。。。

然后最后看dp[strlen(a)]是不是inf,,,

还是把AC代码写出来吧,,,如果之前都没懂看看这个吧,,,其实这个已经不太像我的编程习惯了,,,好多都是借鉴来的。。。

#include <iostream
9baa
>

#include <cstdio>

#include <algorithm>

#include <cstring>

using namespace std;

char s[301],word[50001][51],wordlist[27]={0,2,2,2,3,3,3,4,4,1,1,5,5,6,6,0,7,0,7,7,8,8,8,9,9,9,0},k[510],mid[510];  //借鉴大神的设法

int bb=0,g=0,n,f[101],pre[101],ans[1001];

int check(int ii,int jj)   //检查能否匹配上,,看过有一个strncmp的,,,但是,,,,不太会= =

{

 int j,kk;

 if(wordlist[word[jj][0]-'a'+1]==s[ii]-'0')

 {

  for(j=ii,kk=0;j<ii+strlen(word[jj]);j++,kk++)

   if(wordlist[word[jj][kk]-'a'+1]!=s[j]-'0')return 0;

  return 1;

 }

 return 0;

}

void qsort(int l,int r)//一个归并,,,

{

 int i,j,kk;

 i=l;j=r;

 memset(mid,0,sizeof(mid));

 strcpy(mid,word[(i+j)/2]);

 while(i<=j)

 {

  while(strcmp(word[i],mid)<0)

   i++;

  while(strcmp(word[j],mid)>0)

   j--;

  if(i<=j)

  {

   if(i==j){i++;j--;continue;}

   memset(k,0,sizeof(k));

   strcpy(k,word[i]);

   for(kk=strlen(word[i])-1;kk!=-1;kk--)

    word[i][kk]=0;

   strcpy(word[i],word[j]);

   for(kk=strlen(word[j])-1;kk!=-1;kk--)

    word[j][kk]=0;

   strcpy(word[j],k);

   i++;j--;

  }

 }

 if(j>l)qsort(l,j);

 if(i<r)qsort(i,r);

}

int main()

{

 int gg=0;

 while(1)

 {

  bb=0;

  memset(word,0,sizeof(word));

  memset(s,0,sizeof(s));

  memset(ans,0,sizeof(ans));

  memset(f,127,sizeof(f)); //127是一个神奇的数字可以去查一查哦~~~

  memset(pre,0,sizeof(pre));

  scanf("%s",s);

  if(s[0]=='-')break; //最开始写-1肯定是没有终止的。。。。。。

  scanf("%d",&n);

  for(int i=1;i<=n;i++)  //输入

   scanf("%s",word[i]);

  qsort(1,n);            //之前一直没用,,这样会提高不少效率吧。。不加肯定也能过的(只是我提交的时候一个速度!!??)也就是说整个归并可以去掉

  f[0]=0;     //dp

  for (int i=0;i<strlen(s);i++)

   for (int j=n;j>=1;j--)

      if (i+strlen(word[j])<=strlen(s) && f[i]+1<=f[i+strlen(word[j])] && check(i,j))  //中间那里小于也可,,,,如果词word[j]可以放下而且还符合从i到j而且满足动态规划,,

    f[i+strlen(word[j])]=f[i]+1,pre[i+strlen(word[j])]=j;  //记录每个单词之前的单词是什么!!这步最关键了,,,打印什么的累死了

  if(f[strlen(s)]<=10000000)   //打印就比较简单了不解释了。。。。

  {

   int l=0;

   for (int u=strlen(s);u!=0;u-=strlen(word[pre[u]]))

    ans[++l]=pre[u];

   for (int i=l;i;i--)

    printf("%s ",word[ans[i]]);

            printf("\n");

  }

  else printf("No solution.\n");

 }

 return 0;

}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: