[poj1068]Parencodings[通过率]59%

的题目难不倒哪里去,看到题目的第一反应就是数据结构书里的括号匹配问题,再看看,题目中有一句 well-formed string of parentheses,我猜想是左右括号完美匹配,这样肯定会简单很多。接着看到p、w两组数据感觉两者之间很可能存在函数关系,可以直接转换,想了十来分钟,没想出来,决定用一种很傻的方法。

  • 思路
  1. 用一个数组blk[]来模拟一个栈,保存还没匹配的左括号,大小为size
  2. j<-[0,2*n),每当遇到j=p[i],也即是遇到右括号,则将blk[size-1]存于数组lBlk[](保存左括号位置),右括号位置j保存于rBlk[]
  3. 处理lBlk,当前处理j,计算<j的位置上>lBlk[j]的元素的个数,+1,即为对应的w[j]
  • 问题
  1. 思路2中的rBlk明显多余
  2. 很明显,lBlk、rBlk几乎没有处理,可以确定是赋值处出了错。遇到右括号的语句是if (j == p[cntP]),本意是cntP初值为0,随后根据情况+1,问题就出来遗漏了+1语句,导致只有rBlk[0]也即第一个p[0]时进行了赋值,后面由于cntP一直没有变,当j变化了,p数组中不可能再存在与j不相等的情况。
  3. 前面几行为blk数组的输出,可以看到只成功执行一次(j:3-4),后面再也没有成功。当时在出现问题2的错误输出时,并没有第一时间想到响应的错误,于是把每次循环中blk的状况也输出了,这样错误就更明显的。
  4. 问题2、3给我一个教训:只成功运行一次,很可能是下标没有变化,很容易联想到,在某些情况下忘记重置变量的值也会出现类似的情况。
  5. 在这里,在成功运行第一次后([j:3-4]),数组元素数量一直在减少,在[j:6]后一直增加。对着代码想了十几分钟,完全没有头绪。于是决定跳离代码,看"草稿"(思考思路的时候在本子上写的过程),因为思路简单,很快找到了问题所在:思路2不够完善,在思路2中,p[j]和j第一次相等后再也没有出现相等的情况,修改只需要一句语句:在读入p时对其进行处理:p[j] += j,j是读入p的元素序号。
  6. 这次blk、rBlk正确了,但是lBlk却有错误,在代码中查看相关赋值语句 lBlk[cntLBlk++] = blk[size]; 貌似没有问题,接着我决定检查语句中另外两个变量,cntLBlk明显没有问题,在看size 
                if (j != p[cntP])
             {
                    blk[size] = j;
                    ++size;
             }
                else
                {   /* 遇到右括号 */
                    lBlk[cntLBlk++] = blk[size];
                    rBlk[cntRBlk++] = j;
                    --size;
                    ++cntP;
             }
          从第四行可以看出,size保存的是数组大小,倒数第五句赋值语句引用了一个不存在的地方!明显应该改为size-1
  7. 以上都是只输入一组数据的情况下的,多组怎么办?因为每次的n是不同的,很自然想到利用**w以及malloc realloc,平时多是使用指针动态分配内存,而像这样“一维”大小不相等的没用过,真用起来了发觉还是比较简单,不过因为不熟悉,也会出现一些细节问题,关键代码
            sumN    += n[i];
            w        = (int **)realloc(w, sumN * sizeof(int));
            *(w+i)   = (int *)malloc(n[i] * sizeof(int));
           最惨重的跟头栽在realloc sunN上,突然觉得自己这里用得还是有点小聪明的(菜鸟自我安慰一下)。
  • 总结
  1. 题目不难,而且我觉得肯定有很好的方法而不是像我这么傻这样做的,有用找高手的代码来学习学习。
  2. 可是在细节处理上经常出错,凭借一些测试,还算是比较好地找到了问题所在。
  3. 写博客真累,代码写了接近2小时,可是写这篇逻辑混乱的文章用了接近1小时,可是没办法,不总结,不做笔记的话,题目岂不是白做了?

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

/* #define TESTPRINT 1 */

int main()
{
    int size;           /* 处理到目前最后一个右括号的位置 */
    int t;              /* 测试用例组数 */
    int *n;             /* p元素个数 */
    int *p, **w;
    int *lBlk, *rBlk;   /* 左右括号的位置,11对应 */
    int *blk;
    int sumN = 0;       /* sum of n[0...i] */

    int i, j, k;
    int cntBlk, cntP, cntLBlk, cntRBlk;

    scanf("%d", &t);
    assert(1<=t && t<=10);

    n = (int *)malloc(t * sizeof(int));
    w = (int **)malloc(sizeof(int)); /* 为了能够使用realloc */
    for (i = 0; i < t; ++i)
    {
        scanf("%d", n+i);
        assert(1<=n[i] && n[i]<=20);
       
        sumN    += n[i];
        w        = (int **)realloc(w, sumN * sizeof(int));
        *(w+i)   = (int *)malloc(n[i] * sizeof(int));

        p    = (int *)malloc(n[i] * sizeof(int));
        lBlk = (int *)malloc(n[i] * sizeof(int));
        rBlk = (int *)malloc(n[i] * sizeof(int));
        blk  = (int *)malloc(2 * n[i] * sizeof(int));

        for (j = 0; j < n[i]; ++j)
        {
            scanf("%d", p+j);
            p[j] += j;
            w[i][j]  = 1;
        }

        size = cntBlk = cntP = cntLBlk = cntRBlk = 0;
        for (j = 0; j < 2*n[i]; ++j)
        {
            if (j != p[cntP])
         {
                blk[size] = j;
                ++size;
         }
            else
            {   /* 遇到右括号 */
                lBlk[cntLBlk++] = blk[size-1];
                rBlk[cntRBlk++] = j;
                --size;
                ++cntP;
         }
        }

        for (j = 0; j < n[i]; ++j)
        {
            for (k = 0; k < j; ++k)
         {
                if (lBlk[j] < lBlk[k])
             {
                    ++w[i][j];
             }
         }
        }

#ifdef TESTPRINT
            printf("    w LeftBlanket RightBlanket\n");
            for (j = 0; j < n[i]; ++j)
         {
                printf("%4d %10d  %10d\n", w[i][j], lBlk[j], rBlk[j]);
         }
#endif
    }
#ifndef TESTPRINT
    for (i = 0; i < t; ++i)
    {
        for (j = 0; j < n[i]; ++j)
        {
            printf("%d ", w[i][j]);
        }
        printf("\n");
    }
#endif

    return 0;
}

[time]9-9-2012