zoukankan      html  css  js  c++  java
  • 1055: [HAOI2008]玩具取名

    Description

      某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后
    他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。
    现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。

    Input

      第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。接下来W行,每行两个字母,表示W可
    以用这两个字母替代。接下来I行,每行两个字母,表示I可以用这两个字母替代。接下来N行,每行两个字母,表示N
    可以用这两个字母替代。接下来G行,每行两个字母,表示G可以用这两个字母替代。最后一行一个长度不超过Len的
    字符串。表示这个玩具的名字。

    Output

      一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)如果给的名字不能由任何一个字母
    变形而得到则输出“The name is wrong!”

    Sample Input

    1 1 1 1
    II
    WW
    WW
    IG
    IIII

    Sample Output

    IN

    HINT

    W可以变成II所以IIII可以缩成WW IN均能变成WW所以WW又可以缩成I或者N 所以最终答案应该按照“WING”的顺序

    输出IN 

    [数据范围]
    100%数据满足Len<=200,W、I、N、G<=16
    题解:实话说,看题目时连设都不会设,网上的题解对我来说又太过简洁,还是在老师的教导下才听懂的。。。(唉,有我这种学生真的是麻烦老师了)。
    进入主题,因为c++中的数组不能用字符,所以我们用1表示‘W’,2表示‘I’,以此类推到4.
    方程式中用f[i][j][k]来表示i到j的这段区间内能否表示为k,具体的话不太容易空讲,所以看程序注释吧!
    程序:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    using namespace std;
    int m,n,a,b,ans,c,d,q,r,w[100][4];
    char ch1,ch2;
    bool f[300][300][5];
    string s,s1;
    int main()
    {
    cin>>a>>b>>c>>d;
    for (int i=1;i<=a+b+c+d;i++) 
    //这里我们用一个w数组来储存读入的元素,举个例子,现在w可转换为IG,那么w[i][1]储存I,w[i][2]储存G,w[i][3]则储存w,i的取值由这两个字母是第几个被输入的决定。 if (i>a+b+c) w[i][3]=4; else if (i>a+b) w[i][3]=3; else if (i>a) w[i][3]=2; else w[i][3]=1; cin>>s1; ch1=s1[0]; ch2=s1[1]; if (ch1=='W') w[i][1]=1; else if (ch1=='I') w[i][1]=2;else if (ch1=='N') w[i][1]=3;else if (ch1=='G') w[i][1]=4; if (ch2=='W') w[i][2]=1; else if (ch2=='I') w[i][2]=2;else if (ch2=='N') w[i][2]=3;else if (ch2=='G') w[i][2]=4; } cin>>s; n=s.size(); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) for (int k=1;k<=4;k++) f[i][j][k]=false; //f[i][j][k]表示这段区间内能否由k转换而来。先全都初始化。 for (int i=0;i<=n-1;i++)//原先序列中有的先赋值为true,i从0开始是因为c++中字符串中的第一个字符储存在0号位中。 { if (s[i]=='W') f[i+1][i+1][1]=true; else if (s[i]=='I') f[i+1][i+1][2]=true; else if (s[i]=='N') f[i+1][i+1][3]=true; else if (s[i]=='G') f[i+1][i+1][4]=true; } for (int len=2;len<=n;len++)//枚举区间长度 for (int i=1;i<=n-len+1;i++)//区间左边 { r=i+len-1;//区间右边 m=i;//我们通过m把区间分为两部分 while (m<=r-1)//枚举m { for (int k=1;k<=a+b+c+d;k++)//枚举那些转换公式 f[i][r][w[k][3]]=(f[i][m][w[k][1]])&&(f[m+1][r][w[k][2]])||(f[i][r][w[k][3]]);

    //核心部分,我们去判断由m分开的区间左部分和右部分,是否刚好可以转换成w[k]这个公式的左边字母和右边字母,(即两边都为TRUE)
    若可以,那么这个区间就可以是w[k][3]中的字母转换而来,赋值为TRUE。
    m+=1; } } ans=0; for (int i=1;i<=4;i++) if (f[1][n][i]==true) //按顺序输出 { if (i==1) printf("W"); if (i==2) printf("I"); if (i==3) printf("N"); if (i==4) printf("G"); ans+=1;//记录是否有答案 } if (ans==0) printf("The name is wrong!");//没答案 return 0; }

    唔,复杂度是O(200^3*64),不知是因为实际上没有200^3,还是数据水,还是写着10s的原因,很险地过了。。。。

  • 相关阅读:
    推荐三首适合午休时听的歌
    我要用全身心的爱来迎接每一天!
    过年,别忘了给父母买点东西
    外来务工的人们,你们真是不容易啊!
    新年最新的100句超牛的语言(转)
    最近Gmail扩容的很快
    老板其人
    乒乓爱好者请进:看看你是第几级?
    上海轨道交通地图电子版(提供下载)
    windows XP使用秘籍(包括空当接龙秘籍)
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6231373.html
Copyright © 2011-2022 走看看