10785 - The Mad Numerologist

题意:
大师起名, 要求:
1. 命字里元音和辅音的和最小.
2. 命字里元音都出现在奇数位, 辅音都出现在偶数位(从左往右, 最左边是 1, 依次累加).
3. 每个辅音最多能出现5次, 每个元音最多出现21次.
4. 在满足以上规则的情况下, 要求名字的字典序最小.
注: 看题时理解错题意, 想成要求元音与辅音的差最小, 结果想成动态规划问题, 纠结了一个晚上, 毫无思路, 最后还是看了别人翻译的题目才做出来的. 

思路:
1. 根据输入的名字长度N, 算出需要几个元音和几个辅音.
2. 按元音/辅音代表的值, 从小到大取, 当单个元音/辅音的数量大于5/21时, 就开始取下一个元音/辅音, 直至取到需要的数量为止.
3. 把取到的元音和辅音分别按字典序由小到大进行排序.
4. 把元音和辅音交替输出, 即为所求结果.

要点:
1. 使用 sort 进行排序.
2. 不一定每次都使用 map, 像本题中, 上来的本能直觉就是按照 755 一样进行 map 映射, 其实没必要; 进一步思考可知, 每个元音/辅音所代表的是 2 还是 3 还是 5 根本没有关系, 只需要它们的排列顺序是按照它们的值/字典序从小到大进行排列的即可; 根据以上分析, 可以直接使用数组把 AUEOI, JSBKTCLDMVNWFXGPYHQZR 等存起来, 而无需用 map 来存. 
本文最后的第一个解法更狠, 直接把210位长度时的最终解法列出来, 每次输入名字长度时, 就直接取就可以了; 解法是好解法, 但我不喜欢这样的手动暴力解法.

题目:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=98&page=show_problem&problem=1726

代码:

# include <iostream>
# include <string>
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
# include <cctype>
# include <iterator>
# include <assert.h>
using namespace std;

// 要求的是 元音 和 铺音 的 value 分别最小,不是取它们各自和,
// 然后算它们的差最小
// 好好的问题,因为读题错误,给复杂了无数倍...


// 只要保证 value 小的在前面,同样 value 的时候,字母小的在前面即可
// 不一定死板的按图中给出的结构,设几个 map,或者几个 vector
const char VOVEL[] = "AUEOI";
const char CONSONANT[] = "JSBKTCLDMVNWFXGPYHQZR";

const int V_TIME = 21;    // 每个元音可以出现的次数
const int C_TIME = 5;     // 每个辅音可以出现的次数

int main(int argc, char const *argv[])
{
  #ifndef ONLINE_JUDGE
    freopen("10785_i.txt", "r", stdin);  
    freopen("10785_o.txt", "w", stdout); 
  #endif
  
  int numSet = 0;
  cin >> numSet;

  for (int i=0; i<numSet; i++) {
    printf("Case %d: ", i+1);

    int lengthName;
    cin >> lengthName;

    int numVovel = (lengthName + 1) / 2;       // 元音出现在次数
    int numConsonant = lengthName / 2;         // 辅音出现在次数
    
    string vovel = "";
    for (int i=0; i<numVovel; i++) {
      vovel += VOVEL[i/V_TIME];
    }

    string constant = "";
    for (int i=0; i<numConsonant; i++) {
      constant += CONSONANT[i/C_TIME];
    }

    sort(vovel.begin(), vovel.end());
    sort(constant.begin(), constant.end());

    // 元音也辅音交错输出
    for (int i=0; i<constant.size(); i++) {
      cout << vovel[i] << constant[i];
    }

    // 元音有可能多一个
    if (vovel.size() > constant.size()) cout << vovel[numVovel-1];

    cout << endl;
  }

  return 0;
}

环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE

参考: 以下两处的解法也很不错, 值的借鉴.
http://www.cppblog.com/rakerichard/archive/2011/04/09/143799.html
http://blog.csdn.net/ra_winding/article/details/8218022

你可能感兴趣的:(uva,the,10785,Mad,Numerologist)