前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >程序员进阶之算法练习(三十六)贪心

程序员进阶之算法练习(三十六)贪心

作者头像
落影
发布2019-07-08 00:48:30
6170
发布2019-07-08 00:48:30
举报
文章被收录于专栏:落影的专栏

前言

万物皆贪心。

正文

1.Filling Shapes

题目链接 题目大意: 有基础的三角图案(如下图-左边),需要填充到3xN的大矩形中,要求: 1、不留空隙; 2、没有重叠;

问,有多少种填充的组合方式。

输入: 数字n,表示3*N的大图案宽度;(1≤?≤60) 输出: 多少种填充方式。

Examples input 4 output 4 input 1 output 0

题目解析: n为奇数,则会出现填不满的情况(面积和不相等),此时为0; n为偶数,对于每3*2的6个格子,只有两种组合方式, 那么总共的方案是2^(n/2)的个数。

代码:

代码语言:javascript
复制
    int n;
    cin >> n;
    if (n % 2) {
        cout << 0 << endl;
    }
    else {
        lld ans = 1;
        for (int i = 0; i < n / 2; ++i) {
            ans *= 2;
        }
        cout << ans << endl;
    }
2.Plus from Picture

题目链接 题目大意: h行w列的字符,由'*'和'.'两种符号组成。 问字符中是否仅存在一个'+'号,加号的组成方式: 1、中心点是一个'*'号; 2、中心点的上下左右四个方向有一个或以上的连续'*'符号;

并且,除了这个'+'号,其他左右的字符都是'.'。

如果满足上面的条件,则输出"YES",否则输出"NO"。

输入: 第一行是h, w; (1≤ℎ, ?≤500) 接下来是h行字符,每行有w个。

输出: 满足上面的条件,则输出"YES",否则输出"NO"。

代码语言:javascript
复制
Examples
input
5 6
......
..*...
.****.
..*...
..*...
output
YES
input
3 5
..*..
****.
.*...
output
NO

题目解析: 先找到中心点,判断中心点是否为星号; 然后从四个方向去遍历,每个方向至少有1个星号,得到每个方向的星号; 总的星号是否等于图中的星号。 思考?: 另外一种简单的做法,以5个星号作为基础图案,遍历整个图找到一个最小的+号。 然后延伸去看长度,最后看是否等于所有星号字符数量。

代码地址

3.Beautiful Lyrics

题目链接 题目大意: 一段悦耳的歌词有两行,每行有两个单词,并且要求: 1、第一行的第一个单词中元音数量,和第二行第一个单词相同; 2、第一行的第二个单词中元音数量,和第二行第二个单词相同; 3、第一行的第二个单词中的最后一个元音,和第二行第二个单词相同。

给出n个单词,问最多能拼出多少段悦耳的歌词,每个单词只能用一次。

输入: 第一行n,表示n个单词;(n<=10^5) 接下来n行,每行包括一个单词。 所有单词的字符总数不会超过10^6。

输出: 第一行数字m,表示m段歌词。 接下来是m段歌词,每段两行。

Examples input 14 wow this is the first mcdics codeforces round hooray i am proud about that output 3 about proud hooray round wow first this is i that mcdics am

题目解析: 先去除无关因素的影响,把每个单词的元音提取出来,分类成: 1、单词中元音的长度,分别是len=1、2、3.。。 2、相同长度的元音,分别有a/e/i/o/u 五种结尾的类型。

我们用vec[i][j]表示长度为i,结尾是第j个元音的字符串集合。

再来看看题目的要求,拼出最多的歌词,并且每个单词只能用一次。 而歌词的要求,可以表述为: 1、从相同长度字符串中,取出结尾相同的两个单词,作为第1、2行的第二个单词; 2、从相同长度字符串中,取出长度相同的两个单词,作为第1、2行的第一个单词;

从这里,我们可以得到一个贪心的策略: a.先两个两个的取出所有长度相同并且元音结尾相同的单词,得到x组,这是可能的最大歌词数量; b.从剩下的所有单词中,两两取出所有长度相同的单词,得到y组,ans=min(x, y)组; 如果x>y,那么剩下(x-y)组单词还可以两两组成歌词,此时还有ans+=(x-y)/2;

思考?: 当x>y时,能否取出x组中3个单词,取出1个步骤b剩下的单词,进行配对呢? 答案是可以,但是没有必要。因为步骤b只会剩下0个或者1个某个长度的单词。

代码地址

4. Split a Number

题目链接 题目大意: 有一个字符串str,表示一个数字(没有前导零),现在需要把这个数字分成两个合法的数字,并且希望和尽可能的小。

输入: 第一行,数字n,表示字符串str的长度;(2≤n≤100000) 第二行,字符串str,表示数字; 输出: 最小的和。

Examples input 7 1234567 output 1801 input 3 101 output 11

题目解析: 先不考虑复杂度,对于每个位置pos,只要str[pos]不是字符0,那么就可以切分成两个字符串[0, pos) 和 [pos, n)两部分。 那么可以枚举每一个位置,计算一遍数字的和,最终得到一个最小的数字和。 枚举复杂度是O(N),分割数字和计算数字和是(N),总的复杂度是O(N^2); 因为n最大可以为10w,那么这个复杂度是不可以接受的。

容易知道,很多位置的分割,是不可能成为最小和的值。比如说字符串1234567,如果分割成12+34567或者1+234567是明显重复的计算。 由贪心的思想可以知道,分割出来的字符串a、b的长度应该尽可能接近。 对于长度为n字符串,分割成长度为n/2和n-n/2 ,或者(n+1)/2和n-(n+1)/2的组合是最好的。

那么是否枚举这个情况即可?

并不是!因为存在一个数字0的情况。比如说数字123000321,中间的位置都是0。 综合上面的考虑,我们可以将n/2向左延伸,直到找到一个不为零的数字,作为分割点; 同样的,将(n+1)/2向右延伸,知道找到一个不为零的数字,作为分割点。

然后从上面的两个可能,选择一个最小的值。

时间复杂度O(N);

代码:

代码语言:javascript
复制
    int n;
    cin >> n;
    string str;
    cin >> str;
    
    /*
      所有的切分都是[0, t-1], [t, n)  不同的是t的位置不同
     要求,str[t]不能为字符0.
     
     t可以是n/2,n/2+1等
     */
    
    int x = (n + 1) / 2, y = n / 2;
    string ansX = str, ansY = str;
    
    while (x < str.length() && str[x] == '0') {
        ++x;
    }
    if (x < str.length()) {
        ansX = getSplitSum(str, x);
    }
    
    while (y >= 0 && str[y] == '0') {
        --y;
    }
    if (y >= 0) {
        ansY = getSplitSum(str, y);
    }
    
    cout << getMinStr(ansX, ansY) << endl;

具体方法的实现

总结

题目1:根据题目的特性,可以看出三角形无法填充33的矩形,只能填充32的矩形,那么大问题就可以划分成多个小问题; 题目2:思路比较明显,重点是在于如何找到中心点,我采用的是看每一行每一列的累积星号数量,求交点;别人直接判断一个最小星号,这种做法更加便捷、快速、简练; 题目3:题目的要求看起来很复杂, 通过分析、细化、抽象,提示要素就只有长度、结尾类型两个参数;按照我们归类出来的参数,进行聚合就很容易决策; 题目4:直接的想法很容易想到,比如说从中间分开;但是考虑到前导零的case,用合适的表达方式,会更加容易去计算。

Coding如逆水行舟,不练则废。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.07.06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正文
    • 1.Filling Shapes
      • 2.Plus from Picture
        • 3.Beautiful Lyrics
          • 4. Split a Number
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档