[刷题]算法竞赛入门经典 3-10/UVa1587 3-11/UVa1588

来源:互联网 发布:彩影软件下载 编辑:程序博客网 时间:2024/06/16 12:39

书上具体所有题目:http://pan.baidu.com/s/1hssH0KO
题目:算法竞赛入门经典 3-10/UVa1587:Box
代码:

//UVa1587 - Box#include<iostream>unsigned rect[6];//每个面各有一个一样的对应面,故12个边只要定义6个,其中每偶奇两个代表一个长方形的两个边长bool flag, times[3];//每个面出现的次数(出现第二次时为true)unsigned tmpx, tmpy, now;int main(){    while (scanf("%u%u", &rect[0], &rect[1]) != EOF) {        now = 0;        flag = times[0] = times[1] = times[2] = 0;        if (rect[0] < rect[1]) {            auto t = rect[0];            rect[0] = rect[1], rect[1] = t;        }        for (int i = 1;i < 6;++i) {            scanf("%u%u", &tmpx, &tmpy);            if (flag) continue;            unsigned j;            if (tmpx < tmpy) j = tmpx, tmpx = tmpy, tmpy = j;            for (j = 0;j <= now;++j) {//判断新输入的数据是不是之前已经输入过的某矩形的对面                if (times[j]) continue;//若当前面已经找到其对面,continue继续寻找                if (rect[2 * j] == tmpx&&rect[2 * j + 1] == tmpy) {                    times[j] = 1;//找到对面                    break;                }            }            if (j <= now) continue;//若已经找到对面            if (++now > 2) { flag = 1;continue; }//若出现了第四组不同的面,则不能组成立方体            rect[2 * now] = tmpx, rect[2 * now + 1] = tmpy;        }        if (!flag) {//下面进一步判断是否可以组成Box            unsigned t;//排序,从大到小把每个矩形排序            for (unsigned i = 0;i < 2;++i) {                unsigned  max = 2 * i;                for (unsigned j = i + 1;j < 3;++j)                    if (rect[max] < rect[2 * j]) max = 2 * j;                t = rect[max], rect[max] = rect[2 * i], rect[2 * i] = t;                t = rect[max+1], rect[max+1] = rect[2 * i + 1], rect[2 * i + 1] = t;            }            if (rect[1] < rect[3]) t = rect[1], rect[1] = rect[3], rect[3] = t;            if (rect[2] == rect[4] && rect[3] < rect[5]) t = rect[3], rect[3] = rect[5], rect[5] = t;            if (rect[1] < rect[3]) t = rect[1], rect[1] = rect[3], rect[3] = t;            if (rect[0] != rect[2] || rect[1] != rect[4] || rect[3] != rect[5]) flag = 1;            //for (int i = 0;i < 3;++i) std::cout << rect[2 * i] << '\t' << rect[2 * i + 1] << '\n';        }        printf(flag ? "IMPOSSIBLE\n" : "POSSIBLE\n");    }    return 0;}

分析:因为每个面都有其对面,所以我只定义了3个面的边长,也就是6条边。于是在输入时就可以排除好些impossible的案例。
在代码后半段的进一步判断是否可以组成长方体时,我本来是用的比较烦的方法,比较绕,虽然答案也对而且也不是很耗时间。但是在网上看到了排序法,就是把各个矩形按长宽从大到小排列,排列后很轻松地就可以做出来。于是后来我也用了排序法。(看到了这个好方法我都不好意思把我之前写的贴出来了哈哈。唉,计算机到最后还是拼数学)
比如6个矩形分别为两个5x4的,两个4x3的,两个5x3的,经排序后即为:
5 4
5 3
4 3(对应rect[0]~rect[5])
则只需判断”if (rect[0] != rect[2] || rect[1] != rect[4] || rect[3] != rect[5]) flag = 1;”即可。
然后我又找到了一个大神的代码,其代码如下:
原文链接:http://blog.csdn.net/kun768/article/details/43701899

#include <bits/stdc++.h>using namespace std;struct face{    int x, y;}a[6];bool check(){    if(memcmp(a, a+1, sizeof(face)) || memcmp(a+2, a+3, sizeof(face)) || memcmp(a+4, a+5, sizeof(face))) return false;    if(a[0].x!=a[2].x || a[0].y!= a[4].x || a[2].y!=a[4].y) return false;    return true;}int main(){    while(cin >> a[0].x >> a[0].y >> a[1].x >> a[1].y >> a[2].x >> a[2].y >> a[3].x >> a[3].y >> a[4].x >> a[4].y >> a[5].x >> a[5].y){        for(int i = 0; i < 6; ++i)            if(a[i].x < a[i].y)                swap(a[i].x, a[i].y);        sort(a, a+6, [](const face a, const face b) {return a.x==b.x ? (a.y > b.y) : (a.x > b.x);});        printf("%s\n", check() ? "POSSIBLE" : "IMPOSSIBLE");    }    return 0;}

只需短短23行,效率也极高。真的厉害!然后我发现其实我之前只定义3个面也是没必要的,统一判断一样简洁高效。

题目:算法竞赛入门经典 3-11/UVa1588:Kickdown
代码:

//UVa1588 - Kickdown#include<iostream>#include<cstring>char a[103], b[103];int calculate(char *x, char *y) {    int lenx = strlen(x), leny = strlen(y);    for (int i = 0;i <= lenx;++i) {        const int len = (leny < lenx - i ? leny : lenx - i);        int j;        for (j = 0;j != len;++j)            if (x[i + j] + y[j] >= 100) break;//'2'的ASCII为50,50+50=100        if (j == len)            return (lenx > leny + i ? lenx : leny + i);    }    return 0;}int main(){    while (std::cin >> a >> b) {//scanf输入字符串有bug?        int re_a = calculate(a, b),            re_b = calculate(b, a);        printf("%d\n", re_a < re_b ? re_a : re_b);    }    return 0;}

分析:函数从两者的第一个字符开始比较。需要执行两遍函数,两次函数调换了a、b的位置,理解为:
第一遍:a固定不动,b的第一个字符分别指向a的第1个、第2个、第3个……数字,进行比较全数列。
第二遍:b固定不动,a的第一个字符分别指向b的第1个、第2个、第3个……数字,进行比较全数列。
两遍刚好把所有情况找全。

0 0