Hoodlum1980 (fafa)'s Technological Blog

Languages mainly using and digging: C / CPP, ASM, C#, Python. Other languages:Java.

博客园 首页 新随笔 联系 订阅 管理

(1)ZOJ 1016. Parencodings

题意:把一个括号表达式 S,从 P 编码转换为 W 编码。

P 编码:P = P1,P2, ... , Pn; 其中 Pi  是 S 的第 i 个右括号前面的左括号个数。

W 编码:W = W1, W2, ... , Wn; 对于 S 中的某一个右括号 a,Wi 是从与 a 匹配的左括号开始数起,数到 a 为止的右括号个数。

 

例如:S (((()()())))
P-编码: 4 5 6 6 6 6;
W-编码: 1 1 1 4 5 6;

 

分析:编码的元素个数就是右括号个数,也就是字符串S的一半长度。根据 P 编码建立起 S 字符串,然后根据 W 编码的定义进行转换。这里转换成 W 编码时,虽然是线性扫描,但是存在重复扫描的现象,但并没有利用已经扫描过的信息。潜意识里感觉有可能有优化的余地。不过这个题目规模很小,所以意义不大。

 

zoj_1016
#include <stdio.h>
#include <string.h>

char str[256];

/* 根据 P 编码建立括号表达式 */
void init_from_p(int* p, int length)
{
    int i, j;
    int index = 0;
    int left_count = 0;

    for(i = 0; i < length; i++)
    {
        for(j = 0; j < (p[i] - left_count); j++)
        {
            str[index] = '(';
            ++index;
        }
        left_count = p[i];
        str[index] = ')';
        ++index;
    }
    str[index] = '\0';
}

/* 根据建立的括号表达式转换到 W 编码 */
void convert_to_w(int* w)
{
    int index = 0, depth = 0;
    int right_count = 0;
    char *p = str, *p2;
    while(*p)
    {
        if(*p == ')')
        {
            right_count = 1;
            depth = 1;
            p2 = p - 1;
            while(depth > 0)
            {
                if(*p2 == ')')
                {
                    right_count++;
                    depth++;
                }
                else if(*p2 == '(')
                    depth--;
                --p2;
            }
            w[index] = right_count;
            ++index;
        }
        ++p;
    }
}

int main(int argc, char* argv[])
{
    int t, n, i, j;
    int p[24], w[24];

    scanf("%ld", &t);
    for(i = 0; i < t; i++)
    {
        scanf("%ld", &n);
        for(j = 0; j < n; j++)
            scanf("%ld", p + j);

        memset(str, 0, sizeof(str));
        init_from_p(p, n);
        convert_to_w(w);

        for(j = 0; j < (n - 1); j++)
            printf("%ld ", w[j]);

        printf("%ld\n", w[j]);
    }
    return 0;
}

 

(2)ZOJ 1434. Frogger's For Dinner

题意:一个比较有趣的模拟题目。一只青蛙要横穿过马路,马路中间有双向的 8 车道,上面分布着汽车,用 10 X 10 的网格表示。青蛙可以从选择任何一列向下穿越(之后青蛙只能位于这一列),汽车是“折回式”循环行驶的,即每一行(车道)上的汽车的速度相同(以免发生车祸)。青蛙前进的规则是,青蛙先前进一行,然后所有汽车沿着自己的方向前进 N 格,如果青蛙撞到汽车(重叠),或者汽车走过的轨迹覆盖到了青蛙的位置,则青蛙被杀死。题目要求的本质是判断青蛙是否能够成功穿过马路。

 

分析:如果有汽车的速度是 9,显然该汽车一次移动轨迹可以完整覆盖所有列,则青蛙必然无法穿过。如果一行上摆满 10 辆汽车,显然青蛙也无法穿过。这可以使我们提前确定答案。注意,事后发现下面的代码中直接对 map 做了实时改动,但是也 AC 了,深层原因我没有去想。实际上每尝试一列,都应该使用 map 的全新副本进行模拟,map 本身不要进行任何变动。 

 

zoj_1434
#include <stdio.h>
#include <string.h>

char map[10][10];

/* run one row down. return 1 if the frog is alive */
/* row, col: the position of the frog */
int run(int frogRow, int frogCol)
{
    char tmpRow[12];
    int row, col;
    int x2;
    int bAliving = 1;
    for(col = 0; col < 10; col++)
    {
        if(map[frogRow + 1][col] != 0)
        {
            if(frogRow + 1 <= 4)
                x2 = col - map[frogRow + 1][col];
            else
                x2 = col + map[frogRow + 1][col];
            
            /* the frog is killed ? */
            if(x2 < 0)
            {
                if(frogCol <= col || frogCol >= (x2 + 10))
                    return 0;
            }
            else if(x2 > 9)
            {
                if(frogCol >= col || frogCol <= (x2 - 10))
                    return 0;
            }
            else
            {
                if((frogCol - col) * (frogCol - x2) <= 0)
                    return 0;
            }
        }
    }

    /* make the vehicles run */
    for(row = 1; row <= 8; row++)
    {
        memset(tmpRow, 0, sizeof(tmpRow));
        for(col = 0; col < 10; col++)
        {
            if(map[row][col] != 0)
            {
                if(row <= 4)
                    x2 = col - map[row][col];
                else
                    x2 = col + map[row][col];
                
                if(x2 < 0) x2 += 10;
                else if(x2 > 9) x2 -= 10;

                tmpRow[x2] = map[row][col];
            }    
        }
        memcpy(map[row], tmpRow, 10);
    }
    return 1;
}

int can_across()
{
    int frogRow, frogCol;
    for(frogCol = 0; frogCol < 10; frogCol++)
    {
        frogRow = 0;
        while(1)
        {
            if(run(frogRow, frogCol))
                frogRow++;
            else
                break;

            if(frogRow == 9)
                return 1;
        }
    }
    return 0;
}

int main(int argc, char* argv[])
{
    char line[48];
    int i, j, car_count;
    int bCanAcross;
    while(gets(line) != NULL) /* START */
    {
        bCanAcross = 1; /* resume the frog can across.*/
        memset(map, 0, sizeof(map));
        for(i = 1; i <= 8; i++)
        {
            gets(line);
            car_count = 0;
            for(j = 0; j < 10; j++)
            {
                map[i][j] = line[j * 2] - '0';
                if(map[i][j] == 9)
                    bCanAcross = 0; /* the car's speed is too fast! */
                if(map[i][j] != 0)
                    car_count++;
            }
            if(car_count == 10) /* there are too many cars */
                bCanAcross = 0;
        }
        gets(line); /* END */

        if(bCanAcross)
            bCanAcross = can_across(); /* test which col can across */

        if(bCanAcross) printf("LEFTOVER POSSUM\n");
        else printf("FROGGER\n");
    }
    return 0;
}

 

(3)ZOJ 1707. Automatic Editing

题意:给出一个字符串,和 n 条查找替换规则。依次应用这些规则,然后输出处理后的结果。注意,1)每次都从头开始搜索要替换的字符串;2)一旦使用完了某条规则(即要查找的单词不再出现),之后就不能再次使用这条规则。3)大小写重要。

 

zoj_1707
#include <stdio.h>
#include <string.h>

char find[10][96];
char replace[10][96];

void edit(int n, char* text, char* result)
{
    int i, len;
    char tmp[256];
    char* p = NULL;
    strcpy(tmp, text);
    for(i = 0; i < n; i++)
    {
        len = strlen(find[i]);
        while((p = strstr(tmp, find[i])) != NULL)
        {
            *p = 0;
            sprintf(result, "%s%s%s", tmp, replace[i], p + len);
            strcpy(tmp, result);
        }
    }
}

int main(int argc, char* argv[])
{
    char line[256], result[256];
    int n, i;
    while(1)
    {
        scanf("%ld", &n);
        if(n == 0) break;
        getchar(); /* discard the newline char */
        for(i = 0; i < n; i++)
        {
            gets(find[i]);
            gets(replace[i]);
        }
        gets(line);
        edit(n, line, result);
        printf("%s\n", result);
    }

    return 0;
}

 

(4)ZOJ 1879. Jolly Jumpers

题意:一个由 n 个整数组成的数列,如果相邻元素的差值的绝对值恰好为 1 到 n-1,则该数列被称称为 jolly jumper。

例如:[ 1 4 2 3 ] 是一个 jolly jumper,因为其相邻元素的差值的绝对值分别是 3,2,1。只包含一个元素的数列也定义为 jolly jumper。判断一个给定的数列是否是 jolly jumper。(n < 3000 )

 

zoj_1879
#include <stdio.h>
#include <string.h>
#include <math.h>

char flags[3000];

int main(int argc, char* argv[])
{
    int n, i, lastNum, curNum, tmp;
    int bFindResult, bIsJolly;
    while(scanf("%ld", &n) != EOF)
    {
        memset(flags, 0, sizeof(flags));

        bFindResult = 0;
        bIsJolly = 1;

        scanf("%ld", &lastNum);
        for(i = 1; i < n; i++)
        {
            scanf("%ld", &curNum);

            if(bIsJolly)
            {
                tmp = (int)fabs(curNum - lastNum);
                lastNum = curNum;

                if(tmp == 0 || tmp > n-1 || flags[tmp])
                    bIsJolly = 0;
                else
                    flags[tmp] = 1;
            }
        }

        if(bIsJolly) printf("Jolly\n");
        else printf("Not jolly\n");
    }
    return 0;
}

 

(5)ZOJ 1889. Ones (本文重点)

题意:给出一个不能被 2 和 5 整除的整数 n (0 <= n <= 10000),它的某个倍数用 10 进制表示全部是 1 组成。问符合这个条件的倍数数字由多少个 1 组成。

例如:n = 7 时, 7 * 15873 = 111111;包含 6 个 1,因此结果为 6。

分析:可以很明显的看到,该体产生的数字已经远超过整型类型表达的范围。因此不能试图用整型去寻找该倍数。根据题目,我们只需要确定存在这样一个数字,由 m 个 1 组成,它能被 n 整除。因此只需要试验 m 的值,从 1 开始逐渐增加,直到找到第一个可以被 n 整除的数字为止。我们只需要考虑该数字除以 n 的余数即可(即 mod n)。假设 m 时余数为 remain,容易得出 m = m + 1 时,余数为 (remain * 10 + 1) mod n; 

 

zoj_1889
#include <stdio.h>
int main(int argc, char* argv[])
{
    int n, result, remain;
    while(scanf("%ld", &n) != EOF)
    {
        remain = 1 - 1 / n * n;
        result = 1;
        while(remain != 0)
        {
            result++;
            remain = remain * 10 + 1;
            remain = remain - remain / n * n;
        }
        printf("%ld\n", result);
    }
    return 0;
}


(6)ZOJ 2423. Fractal

题意:要求打印出一个分形图。分形图用X字符表示,定义如下表。要求绘制出度数为 n (n <= 7) 的分形图。

degree box fractal
1 X
2

X  X

  X

X  X

用 B(n-1) 表示 n-1 度  

B(n-1)            B(n-1)

          B(n-1)

B(n-1)            B(n-1)

 

注意:任何一行结尾不可以有多余的空格,否则将会导致“Presentation Error”。

分析:采用根据其递归定义,用递归函数初始化出一个模板,然后滤除每一行结尾的空格后输出即可。代码中使用了 5 个对 B(n-1)的调用,这里实际上 5 个子矩阵的内容是完全一样的,因此只需要调用一次左上角的 B(n-1),然后把它拷贝到其他四个位置即可,这样可以大大减少递归调用次数,提高代码效率。此题目度数很小,因此可以不做出优化。

 

zoj_2423
#include <stdio.h>
#include <string.h>

char map[732][732];

void fractal(int n, int row, int col, int length)
{
    if(n == 1)
    {
        map[row][col] = 'X';
        return;
    }
    else
    {
        int k = length / 3;
        fractal(n-1, row, col, k);
        fractal(n-1, row, col + k * 2, k);
        fractal(n-1, row + k, col + k, k);
        fractal(n-1, row + k * 2, col, k);
        fractal(n-1, row + k * 2, col + k * 2, k);
    }
}

void trim(int length)
{
    int row, col;
    for(row = 0; row < length; ++row)
    {
        for(col = length; col >= 0; --col)
            if(map[row][col] == 'X') break;

        map[row][col + 1] = '\0';
    }
}

void print_map(int length)
{
    int row;
    for(row = 0; row < length; ++row)
        printf("%s\n", map[row]);
    printf("-\n");
}

int main(int argc, char* argv[])
{
    int length[] = { 0, 1, 3, 9, 27, 81, 243, 729 };
    int n;
    while(scanf("%ld", &n) != EOF)
    {
        if(n < 0) break;
        memset(map, ' ', sizeof(map));
        fractal(n, 0, 0, length[n]);
        trim(length[n]);
        print_map(length[n]);
    }
    return 0;
}

 

(7)ZOJ 2886. Look and Say

题意:字符串处理题目。一个字符串 122344111 可以被描述为“1个1,2个2,1个3,2个4,3个1”。因此,其后继是“1122132431”。类似的,1111111111 后继是 101。通常一个字符串的前继不是唯一的,例如 112213243 个 1 组成的数字,后继也是 1122132431。给出一个字符串,输出它的后继。

 

zoj_2886
#include <stdio.h>
void look_say(char *text)
{
    char *p = text;
    int count = 0;
    while(*p)
    {
        count = 1;
        while(p[1] == p[0])
        {
            ++count;
            ++p;
        }
        printf("%ld%c", count, *p);
        ++p;
    }
}

int main(int argc, char* argv[])
{
    char line[1024];
    int n, i;
    scanf("%ld\n", &n);
    for(i = 0; i < n; i++)
    {
        gets(line);
        look_say(line);
        printf("\n");
    }
    return 0;
}


(8)ZOJ 3488. Conic Section

题意:给出方程 ax2+bxy+cy2+dx+ey+f=0 的系数,判断该曲线是圆,椭圆,双曲线还是抛物线。

分析:此题比较坑爹,反复提交失败后,我忍不住搜索了这个题目。原来方程的系数应该定义为浮点数,而不是整数!了解此题后,则此题毫无难度,尽管给了一个比较有趣的平面截双圆锥的图,但纯属科普作用。

 

zoj_3488
#define EQUAL(a, b) (fabs((a)-(b)) < 0.0000001)

#include <stdio.h>
#include <math.h>

int main(int argc, char* argv[])
{
    int T, i;
    double a, b, c, d, e, f;
    scanf("%ld", &T);
    for(i = 0; i < T; i++)
    {
        scanf("%lf %lf %lf %lf %lf %lf", 
            &a, &b, &c, &d, &e, &f);

        if(EQUAL(a*c, 0))
            printf("parabola\n");
        else if(a*c > 0)
        {
            if(EQUAL(a, c))
                printf("circle\n");
            else
                printf("ellipse\n");
        }        
        else if(a*c < 0)
            printf("hyperbola\n");
    }
    return 0;
}

 

posted on 2012-07-07 02:18  hoodlum1980  阅读(2014)  评论(0编辑  收藏  举报